6

I just wanted to ask a simple question - I have a class derived from TLabel as follows:

TMyLabel = class (TLabel)
  ...
  constructor Create(AOwner: TComponent); override;
end;

constructor TMyLabel.Create(AOwner: TComponent); 
begin
  inherited Create(AOwner);
  { some code }
end;

Now, Delphi lets me compile both versions with and without the override. Could you explain what the differences are? Other than being unable to request my own parameters in Create() when overridden. Thanks

Edit: What I mean is - what is the difference between a virtual and a nonvirtual base-descendant constructors? I can always call the inherited constructor by inherited Create(), so what's the point?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Martin Melka
  • 7,177
  • 16
  • 79
  • 138
  • possible duplicate of [Need I to put overload or override words after the constructor declaration in derived class?](http://stackoverflow.com/questions/360597/need-i-to-put-overload-or-override-words-after-the-constructor-declaration-in-de) – Warren P Feb 14 '12 at 16:34
  • The compiler gives you a warning if you don't, right? from linked duplicate; "If you don't do that, the compiler will probably warn you that TMinMatrix's constructor is "hiding" TMatrix's constructor." -- I have yet to run into a practical NEED to hide a component constructor, and TCOmponent in particular seems to rely on a proper virtual-behaviour for Constructors and Destructors, so generally, with TComponent, it's actually close to an error. – Warren P Feb 14 '12 at 16:35
  • Yes, it does. It might be 'hiding' it in the sense that it's not _directly_ descendent, but since I call it by the `inherited` anyway, does it make any difference? – Martin Melka Feb 14 '12 at 16:37
  • Well, it doesn't make any difference to you inside the constructor, but what about if someone then goes and subclasses TMyLabel, you have intentionally broken inheritance chaining, right? My guess is that there is some real cases where you'd want to, but not with TComponents. – Warren P Feb 14 '12 at 16:43
  • also you may take a look at http://stackoverflow.com/questions/3876040/delphi-understanding-constructors – the_joric Feb 14 '12 at 16:46
  • FYI, when inheriting from a VCL control it is standard pracice to inherit from TCustomSomething rather than TSomething (e.g. TCustomLabel instead of TLabel), then you can pick which properties to make public. – Alan Clark Feb 14 '12 at 22:42

2 Answers2

9

Virtual constructors allow for polymorphic instantiation of objects. The classic example of this is Delphi's .dfm streaming mechanism.

The code that reads .dfm files and instantiates forms does not know at compile time which classes to use. The decision is postponed until runtime when it can be made correctly, i.e. when the .dfm file is read. Moreover, you can get the .dfm file mechanism to create custom components that are not part of the VCL and so this .dfm mechanism must be capable of correctly instantiating classes that are not part of the VCL.

The constructor for TComponent is declared like this:

constructor Create(AOwner: TComponent); virtual;

For a component to take part in this mechanism it must declare its constructor with the override directive.

The other key to the process is class references. For example

type
  TComponentClass = class of TComponent;

The code that creates components when reading .dfm files, roughly, looks like this:

var
  ComponentClass: TComponentClass;
  Component, Owner: TComponent;
....
ComponentClass = FindComponentClass(ReadComponentClassName);
Component := ComponentClass.Create(Owner);

Now, if the mechanism did not use virtual constructors then the constructor that would be called would be TComponent.Create. And so your constructor, TMyLabel.Create would never be called.

This is why you must include the override directive on your constructors when deriving from TComponent.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks. However, in case I wanted to allow further derivations of the `TMyLabel` AND I wanted to specify more parameters at creation-time, would it be possible at all? – Martin Melka Feb 14 '12 at 17:02
  • @MartinMelka No that's just not possible if you are going to have the .dfm mechanism instantiate your label. It's always going to call the virtual constructor with the single parameter. You should probably just go along with that constructor and add a method or properties to allow your extra parameters to be supplied post-creation. – David Heffernan Feb 14 '12 at 17:05
2

Well, if I remember Delphi correctly (that was a while ago, though it was good time :) ) when constructor is overriden you'll be able to call it via class references (see this spec as example).

the_joric
  • 11,986
  • 6
  • 36
  • 57
  • Correct, overridden virtual constructors might be invoked by class factories that only know of the base class where the constructor was first declared. – Henrick Hellström Feb 14 '12 at 16:50