The Delphi Language, Part 2 - Methods
(Page 7 of 14 )
Methods are procedures and functions belonging to a given object: They give an object behavior rather than just data. Two important methods of the objects you create are the constructor and the destructor methods, which we just covered. You can also create custom methods in your objects to perform a variety of tasks.
Creating a method is a two-step process. You first must declare the method in the object type declaration, and then you must define the method in the code. The following code demonstrates the process of declaring and defining a method:
type
TBoogieNights = class
Dance: Boolean;
procedure DoTheHustle;
end;
procedure TBoogieNights.DoTheHustle;
begin
Dance := True;
end;
Note that when defining the method body, the fully qualified name—consisting of the class and method names—must be used. It's important also to note that the object's Dance field can be accessed directly from within the method.
Method Types A class type's methods can be declared as normal, static, virtual, class static, class virtual, dynamic, or message. Consider the following example object:
TFoo = class
procedure IAmNormal;
class procedure IAmAClassMethod;
class procedure IAmAStatic; static;
procedure IAmAVirtual; virtual;
class procedure IAmAVirtualClassMethod; virtual;
procedure IAmADynamic; dynamic;
procedure IAmAMessage(var M: TMessage); message WM_SOMEMESSAGE;
end;
Regular Methods
IAmNormal() is a regular method. This is the default method type, and it works similarly to a regular procedure or function call. The compiler knows the address of these methods, so when you call a static method, it's capable of statically linking that information into the executable. Static methods execute the fastest; however, they don't have the capability to be overridden to provide polymorphism.
Class Methods IAmAClassMethod() is a special, Delphi-specific type of static method. Class methods may be called without an instance, and the implementation of class methods are shared among all instances of the given class. However, class methods have a special implicit and hidden Self parameter that is passed by the compiler that allows for the calling of polymorphic (virtual) class methods. Class methods can be plain or virtual. Nonclass or nonstatic elements may not be accessed from within a class method.
Static Methods IAMStatic() is a true, .NET-compatible static method. Like static fields, the implementation of static methods are shared among all instances of the given class. As such, nonstatic elements may not be accessed from within a static method. No Self parameter is passed for static methods, meaning that nonstatic methods may not be called from static methods.
Virtual Methods IAmAVirtual() is a virtual method. Virtual methods are called in the same way as static methods, but because virtual methods can be overridden, the compiler doesn't know the address of a particular virtual function when you call it in your code. The .NET JIT compiler, therefore, builds a Virtual Method Table (VMT) that provides a means to look up function addresses at runtime. All virtual method calls are dispatched at runtime through the VMT. An object's VMT contains all its ancestor's virtual methods as well as the ones it declares.
Dynamic Methods IAmADynamic() is a dynamic method. The .NET compiler maps dynamic methods to virtual methods, unlike the Win32 compiler, which provides for a separate dynamic method dispatching mechanism.
Message Methods IAmAMessage() is a message-handling method. The message directive creates a method that can respond to dynamically dispatched messages. The value after the message keyword dictates what message the method will respond to. In VCL, message methods are used to create an automatic response to Windows messages, and you generally don't call them directly.
Overriding Methods Overriding a method is the Delphi language's implementation of the OOP concept of polymorphism. It enables you to change the behavior of a method from descendant to descendant. Delphi methods can be overridden only if they're first declared as virtual, dynamic, or message. To override a virtual or dynamic method, just use the override directive instead of virtual or dynamic in your descendant object type. To override a message method, the message directive must be repeated and the same message ID used in the ancestor class. For example, you could override the IAmAVirtual(), IAmADynamic(), and IAmAMessage() methods as shown here:
TFooChild = class(TFoo)
procedure IAmAVirtual; override;
procedure IAmADynamic; override;
procedure IAmAMessage(var M: TMessage); message WM_SOMEMESSAGE;
end;
The override directive replaces the original method's entry in the VMT with the new method. If you had redeclared IAmAVirtual and IAmADynamic with the virtual or dynamic keyword instead of override, you would have created new methods rather than overriding the ancestor methods. This will normally result in a compiler warning unless you suppress the warning by adding the reintroduce directive (described shortly) to the method declaration. Also, if you attempt to override a normal method in a descendant type, the static method in the new class hides the method from users of the descendent class.
Method Overloading Like regular procedures and functions, methods can be overloaded so that a class can contain multiple methods of the same name with differing parameter lists. Overloaded methods must be marked with the overload directive, although the use of the directive on the first instance of a method name in a class hierarchy is optional. The following code example shows a class containing three overloaded methods:
type
TSomeClass = class
procedure AMethod(I: Integer); overload;
procedure AMethod(S: string); overload;
procedure AMethod(D: Double); overload;
end;
Reintroducing Method Names
Occasionally, you might want to add a method to one of your classes to replace a virtual method of the same name in an ancestor of your class. In this case, you don't want to override the ancestor method but instead obscure and completely supplant the base class method. If you simply add the method and compile, you'll see that the compiler will produce a warning explaining that the new method hides a method of the same name in a base class. To suppress this error, use the reintroduce directive on the method declaration in the descendant class. The following code example demonstrates proper use of the reintroduce directive:
type
TSomeBase = class
procedure Cooper; virtual;
end;
TSomeClass = class
procedure Cooper; reintroduce;
end;
Self
An implicit variable called Self is available within all object methods. Self is a reference to the class instance that was used to call the method. Self is passed by the compiler as a hidden parameter to all methods. Self is analogous to this in C# and Me in Visual Basic .NET.
This chapter is from Delphi for .NET Developer's Guide, by Xavier Pacheco (Sams, 2004, ISBN: 0-672-32443-1). Check it out at your favorite bookstore today.
Buy this book now. |
Next: Class References and Properties >>
More .NET Articles
More By Xavier Pacheco