Adding an overload in child class - delphi

I have a base class TParent which defines a method without the overload directive:
TParent = class
public
procedure Test();
end;
In a child class TChild, I'm trying to add an overload for the Test procedure.
TChild = class(TParent)
public
procedure Test(AParam : Integer);
end;
On compiling there are no errors neither warnings but if I try to use the TParent.Test with a TChild instance, it gives an E2035 error, like if the parent method was hidden by the child's one:
var
Obj : TChild;
begin
Obj := TChild.Create;
try
Obj.Test();
finally
Obj.Free;
end;
end;
[dcc32 Error] Unit1.pas(52): E2035 Not enough actual parameters
In order to resolve the compiling error, I have to add the overload directive to the TChild.Test declaration.
TChild = class(TParent)
public
procedure Test(AParam : Integer); overload;
end;
It compiles and seems to work, but is it correct even if the TParent.Test declaration has no overload directive at all? Or should I change the name of the child's procedure in case the parent class has not predicted the method to be overloaded?

I believe this is perfectly OK.
The documentation on overloading methods (as opposed to simply overloading non-method procedures and functions) states
A method can be redeclared [in a descendant class (my remark)] using the overload directive. In this case, if the redeclared method has a different parameter signature from its ancestor, it overloads the inherited method without hiding it. Calling the method in a descendent class activates whichever implementation matches the parameters in the call.
This is the only description given, and it isn't crystal clear. Still, the most reasonable interpretation is that it is perfectly fine to do what you suggest. The fact that it works and is used in a lot of existing Delphi source code I think settles it.

Related

Inheriting from generic's parameter doesn't work in Delphi XE

I've been trying to extend a bunch of library classes inheriting from the same base class by overriding a virtual method defined in that base class. The modification is always the same so instead of creating N successors of the library classes I decided to create a generic class parameterized by the library class type, which inherits from the class specified by parameter and overrides the base class' method.
The problem is that the code below doesn't compile, the compiler doesn't allow inheriting from T:
program Project1;
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryClassA = class(LibraryBaseClass)
end;
LibraryClassB = class(LibraryBaseClass)
end;
LibraryClassC = class(LibraryBaseClass)
end;
LibraryClassD = class(LibraryBaseClass)
end;
MyClass<T:LibraryBaseClass> = class(T) //Project1.dpr(20) Error: E2021 Class type required
procedure foo; override;
end;
procedure LibraryBaseClass.foo;
begin
end;
procedure MyClass<T>.foo;
begin
end;
begin
MyClass<LibraryClassA>.Create.foo;
MyClass<LibraryClassB>.Create.foo;
MyClass<LibraryClassC>.Create.foo;
MyClass<LibraryClassD>.Create.foo;
end.
Any ideas how to make this work? Maybe there is a way to trick the compiler into accepting something equivalent because, for example, inheriting from Dictionary<T,T> compiles without problems.
Or what would you do if you had the same goal as I? Keep in mind that in the real situation I need to override more than one method and add some data members.
Thank you
As you've been told already, this is valid with C++ templates, not with C# or Delphi generics. The fundamental difference between templates and generics is that conceptually, each template instantiation is a completely separately compiled type. Generics are compiled once, for all possible types. That simply is not possible when deriving from a type parameter, because you could get constructs such as
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryClassA = class(LibraryBaseClass)
procedure foo; reintroduce; virtual;
end;
LibraryClassB = class(LibraryBaseClass)
end;
MyClass<T:LibraryBaseClass> = class(T)
procedure foo; override; // overrides LibraryClass.foo or LibraryClassA.foo ?
end;
Yet this can work in C++, because in C++ MyClass<LibraryClassA> and MyClass<LibraryClassB> are completely separated, and when instantiating MyClass<LibraryClassA>, foo is looked up and found in LibraryClassA before the base class method is found.
Or what would you do if you had the same goal as I? Keep in mind that in the real situation I need to override more than one method and add some data members.
It is possible to create types at runtime, but almost certainly an extremely bad idea. I have had to make use of that once and would have loved to avoid it. It involves reading the VMT, creating a copy of it, storing a copy of the original LibraryBaseClass.foo method pointer somewhere, modifying the VMT to point to a custom method, and from that overriding function, invoking the original stored method pointer. There's certainly no built-in language support for it, and there's no way to refer to your derived type from your code.
I've had a later need for this in C# once, too, but in that case I was lucky that there were only four possible base classes. I ended up manually creating four separate derived classes, implementing the methods four times, and using a lookup structure (Dictionary<,>) to map the correct base class to the correct derived class.
Note that there is a trick for a specific case that doesn't apply to your question, but may help other readers: if your derived classes must all implement the same interface, and requires no new data members or function overrides, you can avoid writing the implementation multiple times:
type
IMySpecialInterface = interface
procedure ShowName;
end;
TMySpecialInterfaceHelper = class helper for TComponent
procedure ShowName;
end;
procedure TMySpecialInterfaceHelper.ShowName;
begin
ShowMessage(Name);
end;
type
TLabelWithShowName = class(TLabel, IMySpecialInterface);
TButtonWithShowName = class(TButton, IMySpecialInterface);
In that case, the class helper method implementation will be a valid implementation for the interface method.
In Delphi XE and higher, you could also try something completely different: TVirtualMethodInterceptor.
What you are attempting to do is simply not possible with Delphi generics.
For what it is worth, the equivalent code is also invalid in C# generics. However, your design would work with C++ templates.
I probably misunderstood your description of the problem but from your simplified example it seems you could "turn it around" and insert a class in the hierarchy in the middle like this:
program Project1;
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryBaseFooClass = class(LibraryBaseClass)
procedure foo; override;
end;
LibraryClassA = class(LibraryBaseFooClass)
end;
LibraryClassB = class(LibraryBaseFooClass)
end;
LibraryClassC = class(LibraryBaseFooClass)
end;
LibraryClassD = class(LibraryBaseFooClass)
end;
procedure LibraryBaseClass.foo;
begin
end;
procedure LibraryBaseFooClass.foo;
begin
end;
begin
LibraryClassA.Create.foo;
LibraryClassB.Create.foo;
LibraryClassC.Create.foo;
LibraryClassD.Create.foo;
end.

Delphi XE: Can I call virtual constructors with parameters from a classtype-constrained generic type without resigning to hacks?

I'm trying to build a generic ancestor for composite controls. The initial idea looked something like this:
type
TCompositeControl<TControl1: TControl; TControl2: TControl> = class(TWinControl)
private
FControl1,
FControl2: TControl;
public
constructor Create(AOwner: TComponent); override;
end;
TLabelAndEdit = TCompositeControl<TLabel, TEdit>; // simple example for illustration only
constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FControl1 := TControl1.Create(Self);
FControl2 := TControl2.Create(Self);
end;
As you might already be aware, this will trigger compiler error E2568: Can't create new instance without CONSTRUCTOR constraint in type parameter declaration. Adding the constructor constraint doesn't help however as it implies a parameter-less constructor.
Casting the templates to TControl makes the code compilable:
...
FControl1 := TControl(TControl1).Create(Self);
...
...but it results in an Access Violation at runtime.
One hack that would probably work is invoking the constructor via RTTI, but I would consider that a rather dirty solution.
Another hack that essentially works is using class type variables as intermediates:
type
TControlClass = class of TControl;
constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent);
var
lCtrlClass1,
lCtrlClass2: TControlClass;
begin
inherited Create(AOwner);
lCtrlClass1 := TControl1;
FControl1 := lCtrlClass1.Create(Self);
lCtrlClass2 := TControl2;
FControl2 := lCtrlClass2.Create(Self);
end;
Is there a cleaner solution? Also, can somebody explain to me why the classtype-constraint does not suffice for invoking the virtual constructor on the type parameter directly?
Your typecast is bad: TControl(TControl1).Create(Self). That tells the compiler that TControl1 is an instance of TControl, but we know that it's not an instance. It's a class reference. Type-cast it to the class-reference type instead:
FControl1 := TControlClass(TControl1).Create(Self);
An alternate syntax is
FControl1 := TControl1(TControl1.NewInstance); // get memory for object
FControl1.Create(self); // call type-specific constructor
FControl2 := TControl2(TControl2.NewInstance); // get memory for object
FControl2.Create(self); // call type-specific constructor
This is used in Delphi's Classes.pas::CreateComponent
I just can't decide which option is the least ugly!
It seems it the latest delphi version (Seattle) this compiler error is not emitted anymore. I had the same issue we an application, but only when compiled with DelphiXe8 not with delphi Seattle
If your Class uses a constructor without parameters (like TObject), I would suggest to do what the compiler says:
"Add a constructor constraint to the type-parameter declaration"
It should look something like this:
TCompositeControl < Control1: TControl, constructor; TControl2: TControl, constructor > = Class(TWinControl)
If you do so, you should be able to make the necessary call to the constructor of the generic Type.
Howether, I don't know, if it works with a constructor, who needs a parameter.
Please let us know, if it works.

Problems passing a pointer to a constructor as a parameter

I have the following superclass:
unit DlgDefaultForm;
type
TDefaultFormDlg = class(TForm)
published
constructor Create(AOwner: TComponent); reintroduce; virtual;
end;
FormCreateFunc=function(AOwner: TComponent):TDefaultFormDlg;
which is descended by a bunch of forms as follows:
unit Form1
type
TForm1 = class(TDefaultFormDlg)
published
constructor Create(AOwner: TComponent); override;
end;
and created as follows:
unit MainForm;
procedure ShowForm(FormCreate:FormCreateFunc);
begin
(do some stuff)
FormCreate(ScrollBox1);
end;
When I run
ShowForm(#TForm1.Create);
two things happen:
When I step into TForm1.Create, AOwner=nil, even when it didn't in ShowForm.
I get an EAbstractError at the following line:
unit Forms;
(...)
constructor TCustomForm.Create(AOwner: TComponent);
begin
(...)
InitializeNewForm; //EAbstractError
(...)
end;
What am I doing wrong?
EDIT: This of course isn't my exact code.
Delphi constructors take a hidden extra parameter which indicates two things: whether NewInstance needs to be called, and what the type of the implicit first parameter (Self) is. When you call a constructor from a class or class reference, you actually want to construct a new object, and the type of the Self parameter will be the actual class type. When you call a constructor from another constructor, or when you're calling the inherited constructor, then the object instance has already been created and is passed as the Self parameter. The hidden extra parameter acts as a Boolean flag which is True for allocating a new instance but False for method-style calls of the constructor.
Because of this, you can't simply store a constructor in a method pointer[1] location and expect it to work; calling the method pointer won't pass the correct value for the hidden extra parameter, and it will break. You can get around it by declaring the parameter explicitly, and doing some typecasting. But usually it is more desirable and less error-prone to use metaclasses (class references) directly.
[1] That's another problem with your code. You're trying to store a method pointer in a function pointer location. You could do that and still make it work, but you'd need to put the declaration of Self in explicitly then, and you'd also need to pass the metaclass as the first parameter when allocating (as well as passing True for the implicit flag). Method pointers bake in the first parameter and pass it automatically. To make it all explicit, the function pointer equivalent to TComponent.Create is something like:
TComponentCreate = function(Self: Pointer; AOwner: TComponent; DoAlloc: Boolean): Pointer;
Self is a pointer here because it could be of TComponentClass type, or TComponent type, depending on whether DoAlloc is true or false.
You're not using virtual constructors correctly. Try it like this:
type
TDefaultFormDlgClass = class of TDefaultFormDlg;
function Show(FormClass: TDefaultFormDlgClass; AOwner: TComponent): TDefaultFormDlg;
begin
Result := FormClass.Create(AOwner);
end;
...
var
FormClass: TTDefaultFormDlgClass;
...
FormClass := ???;//this is where you specify the class at runtime, e.g. TForm1
MyForm := Show(FormClass, MainForm);
As an aside I do not think you need to reintroduce the constructor in the code you listed.
Based on the information from Barry I tested this code. TSample is a simple class with a paramless constructor. All you need is the pointer to the constructor (#TSample.Create) and the type of the class (TSample). If you've a hashmap key=TClass, value=Pointer ctor you can create any registered type.
type
TObjectCreate = function(Self: TClass; DoAlloc: Boolean): TObject;
var
aSample : TSample;
begin
aSample := TSample(TObjectCreate(#TSample.Create)(TSample, true));

Constructing an Object from a Class Reference

I have a method which constructs an object, calls an Execute method, and frees the object. The type of object is determined by a TClass descendant passed into the method.
Note this is Delphi for Win32 I am talking about, not .NET.
Edit: I should point out that this is Delphi 2006, as it has been noted in answers below that in future versions the NewInstance call may not be required. In my case, however, it is required. As such, I would imagine the answer to my question (is it safe? and does CreateForm() have a potential leak) would need to be answered on the basis that this is Delphi 2006
Edit#2: seems that the solutions given for D2007 & D2009 do in fact work for D2006. I must have picked up the "NewInstance" habit from an earlier version of Delphi...
function TPageClassFactory.TryExecute(ScrnClass: TCustomPageClass): boolean;
//TCustomPageClass = class of TCustomPage
var
ScrnObj: TCustomPage; //TCustomPage defines an abstract Execute() method
begin
Result := FALSE; //default
ScrnObj := TCustomPage(ScrnClass.NewInstance); //instantiate
try
ScrnObj.Create(Self); //NB: Create() and Execute() are *virtual* methods
ScrnObj.Execute;
finally
FreeAndNil(ScrnObj);
end;
Result := TRUE;
end;
What I want to know is whether this is safe - what will happen here if Create() raises an exception?
Looking at a similar example, from Forms.pas.TApplication.CreateForm(), a different approach has been taken to exception handling (I've cut out the irrelevant bits below):
procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
var
Instance: TComponent;
begin
Instance := TComponent(InstanceClass.NewInstance);
TComponent(Reference) := Instance;
try
Instance.Create(Self);
except
TComponent(Reference) := nil;
raise;
end;
end;
In the Forms.pas method, does this mean that memory is leaked when an exception occurs in the Create() method? My understanding was that InstanceClass.NewInstance allocated memory, thus in this case the memory is not being deallocated/released/freed?
You should put the create out of the try finally block.
But a better solution is:
type
TMyClass = class ()
public
constructor Create(...); virtual;
function Execute: Boolean; virtual;
end;
TMyClassClass = class of TMyClass;
procedure CreateExecute(const AClass: TMyClassClass): Boolean;
var
theclass : TMyClass;
begin
theclass := AClass.Create;
try
Result := theclass.Execute;
finally
theclass.Free;
end;
end;
There have been a few questions raised in comments that I'd like to clarify.
First is the continued myth that the constructor needs to be virtual. It does not. Consider this example:
type
TBase = class
constructor Create(x: Integer);
end;
TDerived = class(TBase)
field: string;
end;
TMetaclass = class of TBase;
var
instance: TBase;
desiredClass: TMetaclass;
begin
desiredClass := TDerived;
instance := desiredClass.Create(23);
Assert(instance.ClassName = 'TDerived');
Assert(instance is TDerived);
Assert(instance.field = '');
end;
The created object will be a full-fledged instance of class TDerived. Enough memory will have been allocated to hold the string field, which didn't exist in the base class.
There are two conditions that must be true before you'll need a virtual constructor:
The constructor will be called virtually. That is, you'll have a variable of the base-class metaclass type, and it will hold a value of a derived class, and you will call a constructor on that variable. That's demonstrated in the code above. If all your constructor calls are directly on the class names themselves (i.e., TDerived.Create(23)), then there's nothing to be gained from virtual methods.
A subclass of the base class will need to override the constructor to provide class-specific initialization. If all descendants use the same construction, and only vary in other methods, ten there's no need to make the constructor virtual.
What's important to realize here is that those two rules are no different from the factors that determine when the make any other method virtual. Constructors aren't special in that regard.
The constructor knows which class to construct based not on the class where the constructor was defined, but on the class the constructor was called on, and that class is always passed as a hidden first parameter for every constructor call.
Second is the issue of whether NewInstance should be called in place of or in addition to the constructor. I think other comments have already established that it has nothing to do with compatibility with older Delphi versions. All versions have supported calling constructors on class references without the need for NewInstace. Rather, the confusion comes from looking at TApplication.CreateForm and treating it as an example of how things should be done. That's a mistake.
CreateForm calls NewInstance before calling the constructor because CreateForm's primary reason for existence is to ensure that the global form variable that the IDE declares is valid during the form's own event handlers, including OnCreate, which runs as part of the constructor. If the CreateForm method had done the usual construction pattern, then the global form variable would not yet have had a valid value. Here's what you might have expected to see:
TComponent(Reference) := InstanceClass.Create(Application);
Simple and obvious, but that won't work. Reference won't get assigned a value until after the constructor returns, which is long after the form has triggered some events. If you follow good programming practice and never refer to that variable from within the form class itself, then you'll never notice. But if you follow the documentation's instructions, which are written for an inexperienced audience, then you will refer to the global form variable from within the form's own methods, so the CreateForm method does what it can to make sure it's assigned in time.
To do that, it uses a two-step construction technique. First, allocate memory and assign the reference to the global variable:
Instance := TComponent(InstanceClass.NewInstance);
TComponent(Reference) := Instance;
Next, call the constructor on the instance, passing the TApplication object as the owner:
Instance.Create(Self);
It's my opinion that CreateForm should be called exactly once in any program. I'd prefer zero times, but it has the side effect of defining Application.MainForm, which is important for other aspects of a Delphi program.
Third is the notion that it's unusual for an object to call a constructor on itself.
In fact, this happens all the time. Every time you call an inherited constructor, you're calling a constructor on an object that already exists. The inherited constructor is not allocating a new object. Likewise, the VCL has some examples of non-inherited calls of constructors. TCustomForm.Create delegates much of its construction tasks to its CreateNew constructor.
Re your question about memory being leaked when Create() raises an exception: You should try it out for yourself. I just did on Delphi 2007, and with your code FastMM4 shows an error dialog about the attempt to call a virtual method on an already freed object, namely Destroy(). So the exception in Create will already lead to the destructor being called and the memory being freed, so your code is actually wrong. Stick to the idiom used in the answer by Gamecat, and everything should work.
Edit:
I just tried on Delphi 4, and the behaviour is the same. Test code:
type
TCrashComp = class(TComponent)
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
constructor TCrashComp.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
raise Exception.Create('foo');
end;
destructor TCrashComp.Destroy;
begin
Beep;
inherited Destroy;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
C: TComponent;
begin
C := TComponent(TCrashComp.NewInstance);
try
C.Create(nil);
C.Tag := 42;
finally
C.Free;
end;
end;
With FastMM4 the Free in the finally block gives the same error, because C has been freed already. On application shutdown the exception and the exception string are reported as memory leaks, though. This is however not a problem with the code, but with the runtime.
Edit:
Didn't fully remember how it was in old delphi versions but apparently this should work in all based on other replies.
Note, Create has been calling Destroy on fail for as long as I can remember. It shouldn't be after I think.
Code would be:
procedure TPageClassFactory.TryExecute(ScrnClass: TCustomPageClass);
var
ScrnObj: TCustomPage;
begin
ScrnObj := ScrnClass.Create(Self); // Exception here calls the destructor
try
ScrnObj.Execute; // Exception here means you need to free manually
finally
FreeAndNil(ScrnObj); // Be free!
end;
end;
I removed the result returned by the original function as it can never be false, only "unassigned" (exception) or true. You could after all get an exception before you assign result to false. ;)

How can I detect if a Delphi class has a virtual constructor?

For example, is there a way to find out that this class has a virtual constructor (at runtime)?
TMyClass = class(TObject)
MyStrings: TStrings;
constructor Create; virtual;
end;
For example, in this code I would like to test if the class referenced by Clazz has a virtual constructor:
procedure Test;
var
Clazz: TClass;
Instance: TObject;
begin
Clazz := TMyClass;
Instance := Clazz.Create;
end;
Is there a simple solution, for example using RTTI, which works in Delphi 6 to 2009?
Looking through the TypInfo unit, it doesn't look like there's any way to tell if a method is virtual using RTTI or not. If you have a class reference, though, you can probably roll your own method by examining the VMT.
According to Allen Bauer, in an answer to this question, you can find the end of the VMT immediately before the value pointed to by vmtClassName. The first user-defined virtual method (if any) is found at the address of the class reference. In other words, pointer(Clazz)^. Now that you know the start and end points of the user-defined section of the VMT, it shouldn't be too difficult to make a while loop that compares each pointer in the table against the Code section of a method pointer to Clazz.create casted to a TMethod. If you get a match, then it's a virtual method. If not, then it isn't.
Yes, it's a bit of a hack, but it'll work. If anyone can find a better solution, more power to them.
You know, the more I think about it, the less I like the answer I gave that ended up getting accepted. The problem is, the code as written can only deal with information known at compile-time. If Clazz is defined as a TClass, then putting Clazz.Create in a TMethod is always going to give you a method pointer to TObject.Create.
You could try defining Clazz as a "class of TMyClass". Thing is, you've already got a virtual constructor there, so it's going to give you the highest-level constructor it can reach that overrides that constructor. But from your comments, it looks like what you're trying to find is a non-virtual constructor (using reintroduce;) that will break your virtual construction. Most likely you're using a factory pattern, where this could be an issue.
The only solution to that is to use RTTI to find the constructor that's actually attached to the class. You can get a method pointer for "the method named Create" and use it in the trick I explained in my other answer. To do this, your base virtual constructor has to be declared published. This will force all methods that override it to also be published. Problem is, someone can still use reintroduce; to declare a non-published constructor higher up, and your scheme comes crashing to the ground. You don't have any guarantees about what descendant classes will do.
There's no technical solution to this question. The only thing that really works is education. Your users need to know that this class is instantiated by a factory (or whatever your reason is for needing a virtual constructor) and that if they reintroduce the constructor in a derived class, it could break things. Put a note in the documentation to this effect, and a comment in the source code. That's pretty much all you can do.
Michael,
I get your question, but since your sourcecode does not compile, I think you miss the point of your question ;-)
My answer is a bit of an elaboration on what Mason tried to explain in his second answer.
The issue at hand is that your question imples that you have a 'class reference' (like TClass or TComponentClass) that references to a base class that has a virtual constructor.
However, TClass doesn't (TClass references a class that has a non-virtual constructor), but TComponentClass does.
You see the difference when disassembling the call to the constructor by using a class reference.
When you call a virtual constructor through a class reference, the code is slightly different than when you call a non-virtual constructor:
calling a virtual constructor has an indirection
calling a non-virtual constructor does a direct call
This disassembly shows what I mean:
TestingForVirtualConstructor.dpr.37: ComponentClassReference := TMyComponentClass;
00416EEC A1706D4100 mov eax,[$00416d70]
TestingForVirtualConstructor.dpr.38: Instance := ComponentClassReference.Create(nil); // virtual constructor
00416EF1 33C9 xor ecx,ecx
00416EF3 B201 mov dl,$01
00416EF5 FF502C call dword ptr [eax+$2c]
TestingForVirtualConstructor.dpr.39: Instance.Free;
00416EF8 E8CFCDFEFF call TObject.Free
TestingForVirtualConstructor.dpr.41: ClassReference := TMyClass;
00416EFD A1946E4100 mov eax,[$00416e94]
TestingForVirtualConstructor.dpr.42: Instance := ClassReference.Create(); // non-virtual constructor
00416F02 B201 mov dl,$01
00416F04 E893CDFEFF call TObject.Create
TestingForVirtualConstructor.dpr.43: Instance.Free;
00416F09 E8BECDFEFF call TObject.Free
So when you have a variable of type class reference for which the constructor is virtual, and you call that constructor through that variable, you are sure that the actual class in that variable will have a virtual constructor.
You can not determine on which actual class that constructor is implemented (well, not without extra debugging info, for instance from the .DCU, .MAP, .JDBG, or other sources).
Here is the example code that does compile:
program TestingForVirtualConstructor;
{$APPTYPE CONSOLE}
uses
Classes, SysUtils;
type
TMyComponentClass = class(TComponent)
MyStrings: TStrings;
constructor Create(Owner: TComponent); override;
end;
constructor TMyComponentClass.Create(Owner: TComponent);
begin
inherited;
end;
type
TMyClass = class(TObject)
MyStrings: TStrings;
constructor Create();
end;
constructor TMyClass.Create();
begin
inherited;
end;
procedure Test;
var
// TComponentClass has a virtual constructor
ComponentClassReference: TComponentClass;
ClassReference: TClass;
Instance: TObject;
begin
ComponentClassReference := TMyComponentClass;
Instance := ComponentClassReference.Create(nil); // virtual constructor
Instance.Free;
ClassReference := TMyClass;
Instance := ClassReference.Create(); // non-virtual constructor
Instance.Free;
end;
begin
try
Test;
except
on E: Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
To get back to your original question:
When your class reference references a base class having a virtual constructor, you are sure that you will always call a virtual constructor using an indirection.
When your class reference references a base class having a non-virtual constructor, you are sure that you will always call a non-virtual constructor using a direct call.
Hope this sheds some more light on your question.
--jeroen

Resources