Delphi Programming Guide
Delphi Programmer 

Menu  Table of contents

Part I - Foundations
  Chapter 1 – Delphi 7 and Its IDE
  Chapter 2 – The Delphi Programming Language
  Chapter 3 – The Run-Time Library
  Chapter 4 – Core Library classes
  Chapter 5 – Visual Controls
  Chapter 6 – Building the User Interface
  Chapter 7 – Working with Forms
Part II - Delphi Object-Oriented Architectures
  Chapter 8 – The Architecture of Delphi Applications
  Chapter 9 – Writing Delphi Components
  Chapter 10 – Libraries and Packages
  Chapter 11 – Modeling and OOP Programming (with ModelMaker)
  Chapter 12 – From COM to COM+
Part III - Delphi Database-Oriented Architectures
  Chapter 13 – Delphi's Database Architecture
  Chapter 14 – Client/Server with dbExpress
  Chapter 15 – Working with ADO
  Chapter 16 – Multitier DataSnap Applications
  Chapter 17 – Writing Database Components
  Chapter 18 – Reporting with Rave
Part IV - Delphi, the Internet, and a .NET Preview
  Chapter 19 – Internet Programming: Sockets and Indy
  Chapter 20 – Web Programming with WebBroker and WebSnap
  Chapter 21 – Web Programming with IntraWeb
  Chapter 22 – Using XML Technologies
  Chapter 23 – Web Services and SOAP
  Chapter 24 – The Microsoft .NET Architecture from the Delphi Perspective
  Chapter 25 – Delphi for .NET Preview: The Language and the RTL
       
  Appendix A – Extra Delphi Tools by the Author
  Appendix B – Extra Delphi Tools from Other Sources
  Appendix C – Free Companion Books on Delphi
       
  Index    
  List of Figures    
  List of tables    
  List of Listings    
  List of Sidebars  

 
Previous Section Next Section

Classes and Objects

Delphi is based on OOP concepts, and in particular on the definition of new class types. The use of OOP is partially enforced by the visual development environment, because for every new form defined at design time, Delphi automatically defines a new class. In addition, every component visually placed on a form is an object of a class type available in or added to the system library.

Note 

The terms class and object are commonly used and often misused, so let's be sure we agree on their definitions. A class is a user-defined data type, which has a state (its representation or internal data) and some operations (its behavior or its methods). An object is an instance of a class, or a variable of the data type defined by the class. Objects are actual entities. When the program runs, objects take up some memory for their internal representation. The relationship between object and class is the same as the one between variable and type.

As in most other modern OOP languages (including Java and C#), in Delphi a class-type variable doesn't provide the storage for the object, but is only a pointer or reference to the object in memory. Before you use the object, you must allocate memory for it by creating a new instance or by assigning an existing instance to the variable:

var 
  Obj1, Obj2: TMyClass;
begin 
  // assign a newly created object
  Obj1 := TMyClass.Create; 
  // assign to an existing object
  Obj2 := ExistingObject; 

The call to Create invokes a default constructor available for every class, unless the class redefines it (as described later). To declare a new class data type in Delphi, with some local data fields and some methods, use the following syntax:

type
  TDate = class
    Month, Day, Year: Integer;
    procedure SetValue (m, d, y: Integer);
    function LeapYear: Boolean;
  end;
Note 

The convention in Delphi is to use the letter T as a prefix for the name of every class you write and every other type (T stands for Type). This is just a convention—to the compiler, T is just a letter like any other—but it is so common that following it will make your code easier for other developers to understand.

A method is defined with the function or procedure keyword, depending on whether it has a return value. Inside the class definition, methods can only be declared; they must be then defined in the implementation portion of the same unit. In this case, you prefix each method name with the name of the class it belongs to, using dot notation:

procedure TDate.SetValue (m, d, y: Integer);
begin
  Month := m;
  Day := d;
  Year := y;
end;
   
function TDate.LeapYear: Boolean;
begin
  // call IsLeapYear in SysUtils.pas
  Result := IsLeapYear (Year);
end;
Tip 

If you press Ctrl+Shift+C while the cursor is within the class definition, the Class Completion feature of the Delphi editor will generate the skeleton of the definition of the methods declared in a class.

This is how you can use an object of the previously defined class:

var
  ADay: TDate;
begin
  // create an object
  ADay := TDate.Create;
  try
    // use the object
    ADay.SetValue (1, 1, 2000);
    if ADay.LeapYear then
      ShowMessage ('Leap year: ' + IntToStr (ADay.Year));
  finally
    // destroy the object
    ADay.Free;
  end;
end;

Notice that ADay.LeapYear is an expression similar to ADay.Year, although the first is a function call and the second a direct data access. You can optionally add parentheses after the call of a function with no parameters. You can find the previous code snippets in the source code of the Dates1 example; the only difference is that the program creates a date based on the year provided in an edit box.

Note 

The code snippet above uses a try/finally block to ensure the destruction of the object even in the case of exceptions in the code. You can find an introduction to the topic of exceptions at the end of this chapter.

More on Methods

There is a lot more to say about methods. Here are some short notes about the features available in Delphi:

  • Delphi supports method overloading. This means you can have two methods with the same name, provided that you mark the methods with the overload keyword and that the parameter lists of the two methods are sufficiently different. By checking the parameters, the compiler can determine which version you want to call.

  • Methods can have one or more parameters with default values. If these parameters are omitted in the method call, they will be assigned the default value.

  • Within a method, you can use the Self keyword to access the current object. When you refer to local data of the object, the reference to self is implicit. For example, in the SetValue method of the TDate class listed earlier, you use Month to refer to a field of the current object, and the compiler translates Month into Self.Month.

  • You can define class methods, marked by the class keyword. A class method doesn't have an object instance to act upon, because it can be applied to an object of the class or to the class as a whole. Delphi doesn't (currently) have a way to define class data, but you can mimic this functionality by adding global data in the implementation portion of the unit defining the class.

  • By default, methods use the register calling convention: (simple) parameters and return values are passed from the calling code to the function and back using CPU registers, instead of the stack. This process makes method calls much faster.

Creating Components Dynamically

To emphasize the fact that Delphi components aren't much different from other objects (and also to demonstrate the use of the Self keyword), I've written the CreateComps example. This program has a form with no components and a handler for its OnMouseDown event, which I've chosen because it receives as a parameter the position of the mouse click (unlike the OnClick event). I need this information to create a button component in that position. Here is the method's code:

procedure TForm1.FormMouseDown (Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  Btn: TButton;
begin
  Btn := TButton.Create (Self);
  Btn.Parent := Self;
  Btn.Left := X;
  Btn.Top := Y;
  Btn.Width := Btn.Width + 50;
  Btn.Caption := Format ('Button at %d, %d', [X, Y]);
end;

The effect of this code is to create buttons at mouse-click positions, as you can see in Figure 2.1. In the code, notice in particular the use of the Self keyword as both the parameter of the Create method (to specify the component's owner) and the value of the Parent property. I'll discuss these two elements (ownership and the Parent property) in Chapter 4, "Core Library Classes."

Click To expand
Figure 2.1: The output of the CreateComps example, which creates Button components at run time

When writing code like this, you might be tempted to use the Form1 variable instead of Self. In this specific example, that change wouldn't make any practical difference; but if there are multiple instances of a form, using Form1 would be an error. In fact, if the Form1 variable refers to the first form of that type being created, then by clicking in another form of the same type, the new button will always be displayed in the first form. The button's Owner and Parent will be Form1, not the form the user has clicked. In general, referring to a particular instance of a class when the current object is required is bad OOP practice.


 
Previous Section Next Section


 


 

Delphi Sources


Copyright © 2004-2024 "Delphi Sources" by BrokenByte Software. Delphi Programming Guide
ร๐๓๏๏เ ยส๎ํ๒เ๊๒ๅ   Facebook   ั๑๛๋๊เ ํเ Twitter