Saturday, October 11, 2003

Class references and virtual constructors

What are some of the things that makes Delphi unique? One thing that Delphi provides is virtual constructors. So how do you make a virtual call to a constructor when, by definition, you don't have an instance? This is accomplished by using a one of the other somewhat unique Delphi constructs, the class reference. A class reference variable holds, not a class instance, but a class type. They also follow the same assignment compatibility rules that a class type variable does.

So what is this good for? What if you didn't know what class to construct at compile-time? Well, class references and virtual constructors to the rescue. So you can now have a hierarchy of classes where you can decide at run-time which classes to construct and use.

TComponent = class
constructor Create; virtual;

TComponentClass = class of TComponent;


TMyComponent = class(TComponent)
constructor Create; override;

TMyOtherComponent = class(TComponent);
constructor Create; override;

function CreateComponent(AComponentRef: TComponentClass): TComponent;
Result := AComponentRef.Create;

procedure CreateComponents;
AComponent: TComponent;
AnotherComponent: TComponent;
AComponent := CreateComponent(TMyComponent);
AnotherComponent := CreateComponent(TMyOtherComponent);

In the above example, the function CreateComponent will create any component that is of type TComponent or any descendant thereof. TComponent is declared to have a virtual constructor. By passing in a specific class reference type into CreateComponent, any component descendant can be created.

Still not convinced? Well this is exactly how the Delphi form designer functions. When you register your components into the IDE, you are passing a class reference. This is then stored internally in a class reference variable associated with a particular tool palette item. When the user selects the palette item and clicks on the surface of the form designer, that class reference is passed into the designer where a component instance is constructed by calling the virtual constructor through that class reference.

There you have it. Hopefully you can see the power and simplicity of using virtual constructors and class references.