Constructing an Object from a Class Reference - delphi

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. ;)

Related

Delphi raise exception in constructor

SITUATION
I am going to write a class and the constructor is a custom one that I have made because I need to initialize some values. This is the code I've written so far:
type
TCombinatorio = class(TObject)
private
valN, valK: integer;
result: double;
public
property K: integer read valK;
property N: integer read valN;
constructor Create(valN: integer; valK: integer);
end;
constructor TCombinatorio.Create(valN: Integer; valK: Integer);
begin
inherited Create;
Self.valN := valN;
Self.valK := valK;
if ((valN < 0) or (valK < 0)) then
begin
raise Exception.Create('N and K must be >= 0');
end;
end;
Since I am going to do some math calculations, I need to avoid negative numbers.
QUESTION
Can I raise an exception in the constructor in that way? I am running the code in this way:
procedure TForm1.Button1Click(Sender: TObject);
var a: TCombinatorio;
b: string;
begin
a := TCombinatorio.Create(5,-2);
try
//some code
finally
a.Free;
end;
end;
As you can see here I have wrong parameters for my constructor, since the second is negative. I also cannot understand (according with the code of my constructor) if the a.Free inside the finally is really needed because when the constructor raises the exception, the destructor is called.
I thought to include the a := TCombinatorio.Create(5,-2); inside the try-finally block to avoid the problem but I am not sure. What do you think?
Your code is absolutely fine and correct. Raising exceptions from constructors is perfectly respectable. As you know the destructor is called.
You ask about this code:
a := TCombinatorio.Create(5,-2);
try
//some code
finally
a.Free;
end;
You are worried that Free will be called after the object has already been destroyed. That cannot happen. If an exception is raised in the constructor then it propagates up the call stack. That happens before the try block begins and so the finally block does not execute. Indeed the assignment to a does not happen.
Moving the creation inside the try would be disastrous and is in fact an incredibly common mistake. Suppose you did that:
// WARNING THIS CODE IS DEFECTIVE
try
a := TCombinatorio.Create(5,-2);
//some code
finally
a.Free;
end;
Now if an exception is raised then Free is called but on what? The variable a is not initialized. Even if it was, which it isn't, that would still be a double free.
OK, first you can raise an exception in the constructor, and yes it does call the destructor as a consequence. The code you show is fine. But I think you misunderstand what your code does. And to put the constructor inside a try finally block would be wrong. The point I think that you are missing is that if your constructor fails the try...finally block never gets executed and so the free is not executed. You should not call free if the constructor does not succeed, which is why you should not put the constructor inside the try...finally block.
First of all I would say that you cannot avoid exceptions in constructors so it cannot be an anti-pattern. If you check Delphi source code you will find number of places where exception is raised in constructor. For example
constructor TCustomForm.Create(AOwner: TComponent);
begin
// ... skipped some lines
if not InitInheritedComponent(Self, TForm) then
raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
The only thing you should know is that Delphi will automatically call the destructor if an exception escapes from the constructor. Actually it means that your destructor may be executed on a partially constructed object and it is your responsibility to write destructor properly. See TObject.Destroy documentation, and pay your special attention to the below quote:
Note: If an exception escapes from the constructor, the destructor is called to destroy the partially constructed object instance that
failed to initialize completely. Therefore, destructors should check
that allocated resources such as handles were actually allocated
before trying to release them, since their value might be zero.
PS In general you should assume that each line of code may raise an exception, but please do not be a paranoiac ;)
In that case I am usual add methods which check the data:
.. = class
function DataValid : boolean;
...
end;
Lots of benefit:
no exception in constructor. It simple copies its parameters to in-class fields.
special destructor for partially created class not needed.
simplicity of code.

Delphi manage free memory

SITUATION
I am studying Delphi from Marco Cantu's book and I already have experience with OOP because I usually work with Java and PHP. To better understand what I'm reading I've made this test:
type
TFraction = class
private
number: double;
num, den: integer;
fraction: string;
function hcf(x: integer; y: integer): integer;
public
constructor Create(numerator: integer; denominator: integer); overload;
constructor Create(value: string); overload;
function getFraction: string;
end;
This is a super easy class that converts a decimal number into a fraction. I'm not including the other parts of the code where I define constructors and functions since they aren't useful for my question. I am creating the object in this way.
var a: TFraction;
begin
a := TFraction.Create(225, 35);
ShowMessage(a.getFraction);
//The output of ^ is 45/7
a.Free;
end;
QUESTION
From what I've learnt, I know that I have to get rid of the object once I've used it and in fact I am using the Free. In this way I free the memory and I avoid memory leaks.
By the way I see that I also have the possibility to override a destructor. I don't understand very well the behavior of the Free and the Destroy. I use the Free when I have to get rid of an object that I don't need anymore. When I override a destructor I can free the object and also make other actions?
In short, when is it good to use the Free? And when should I prefer the Destroy?
In general, the destructor is used if you need to do something during object destruction which otherwise wouldn't be done automatically. Like freeing memory that you initialize in the constructor. In your example, there is no need to override the destructor, since (presumably) you don't create anything which needs to be destroyed manually.
Also, keep in mind that Destroy is not intended to be called by you at all - neither internally or externally. Free automatically takes care of calling that for you - with a little extra work going on. Free checks if the object is nil or not, and only calls Destroy if it's not nil.
Take this for example:
type
TMyObject = class(TObject)
private
FSomeOtherObject: TSomeOtherObject;
public
constructor Create;
destructor Destroy; override;
end;
constructor TMyObject.Create;
begin
inherited;
FSomeOtherObject:= TSomeOtherObject.Create;
end;
destructor TMyObject.Destroy;
begin
FSomeOtherObject.Free;
inherited;
end;
Just as an added note, the usage I see above is missing something. What if the code between Create and Free raises some exception? The procedure would exit, and it would never be free'd. So instead, you should use a try / finally block...
a := TFraction.Create(225, 35);
try
ShowMessage(a.getFraction);
finally
a.Free;
end;
This would ensure that no matter what happens between try and finally, the code between finally and end will always be called.
By the way I see that I also have the possibility to override a destructor. I don't understand very well the behavior of the Free and the Destroy.
Free() calls the destructor if the object pointer is not nil.
Destroy() is the actual destructor.
I use the Free when I have to get rid of an object that I don't need anymore. When I override a destructor I can free the object and also make other actions?
Yes. The destructor is called when the object is in the process of being destroyed. Overriding the destructor is a good place to perform cleanup actions related to the object that is being destroyed.
In short, when is it good to use the Free? And when should I prefer the Destroy?
You can call Destroy() directly, but it is generally preferred to call Free() instead and let it call Destroy() for you.

Instantiated COM Component gets invalid after leaving method (but not its scope)

I am currently testing two external COM components. I have big issue with one of them, but I cannot really find reason behind such behavior. Let me provide some example.
const
CLASS_SomeClas: TGUID = '{SomeGUID}';
type
ISomeInterface = interface(IDispatch)
['{SomeGUID}']
function SomeMethod(const AInput: WideString): WideString; safecall;
end;
TWrappingClass = class(TObject)
strict private
FInstance: ISomeInterface;
procedure CreateInstance;
public
procedure DoYourActualJob;
end;
procedure TWrappingClass.CreateInstance;
begin
FInstance := CreateComObject(CLASS_SomeClass) as ISomeInterface;
dbg(FInstance._AddRef); // Debugs 3
dbg(FInstance._AddRef); // Debugs 4
dbg(FInstance.Release); // Debugs 3
dbg(FInstance._AddRef); // Debugs 4
FInstance.SomeMethod(''); //Runs as expected
end;
procedure TWrappingClass.DoYourActualJob;
begin
CreateInstance;
dbg(FInstance._AddRef); //Debugs -1!
FInstance.SomeMethod(''); //AV
end;
As provided with example instance gets invalid after it leaves CreateInstance method. Component is designed to work with many sequential calls of SomeMethod and it does work when called inside single method.
Could someone give me clue what is actually happening there, why my instance gets invalid? Is it problem with my code, with Delphi or with component's code? When I change the implementation of TWrappingClass to another vendor (that is I change both ISomeInterface and CLASS_SomeClass) then everything works fine.
EDIT:
Behaviour does not change when I don't even call SomeMethod. That is after I leave CreateInstance, call to _AddRef returns -1. Component I am testing is here CadEditorX Probably I am not allowed to attach the OCX without violating its license.
You state clearly in the question that the erroneous behaviour only occurs with one specific COM object. Given this fact, and that Delphi's COM reference counting is known to work correctly, the only reasonable conclusion is that the fault lies in this specific COM object.
Your only recourse of action is to contact the vendor of this COM object and file a bug report with them.
One thing to look at, with a view to a possible work around, is how you are creating the object. You use CreateComObject. This receives a class ID and returns IUnknown. It calls CoCreateInstance passing the class ID, and requesting the IUnknown interface. You then need to query for your interface, ISomeInterface. So your code looks like this:
var
iunk: IUnknown;
intf: ISomeInteface;
....
CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,
IUnknown, iunk);
iunk.QueryInterface(ISomeInterface, intf);
The fact that you have two interface variables, one IUnknown and one ISomeInterface explains why you see the reference count that you do. Now, you might think that you only have one interface variable, but that's not the case. There are two, only one of them is an implicit local. You can see this by looking at the compiled code and stepping through under the debugger.
This code:
procedure TWrappingClass.CreateInstance;
begin
FInstance := CreateComObject(CLASS_SomeClass) as ISomeInterface;
end;
is compiled as if it were this (ignoring error checking):
procedure TWrappingClass.CreateInstance;
var
iunk: IUnknown;
begin
iunk := CreateComObject(CLASS_SomeClass);
try
FInstance := CreateComObject(CLASS_SomeClass) as ISomeInterface;
finally
iunk := nil;
end;
end;
Perhaps the COM component cannot handle the call to Release made on its IUnknown interface.
So, you could try to work around this by using CoCreateInstance instead of CreateComObject. Pass ISomeInterface as the riid parameter.
OleCheck(CoCreateInstance(CLASS_SomeClass, nil, CLSCTX_INPROC_SERVER
or CLSCTX_LOCAL_SERVER, ISomeInterface, FInstance));

How to interrupt component from loading in its constructor?

I would like to add to my component the conditional state when the component cannot be loaded and inform its user (developer) that this component cannot be loaded in design time and target user at runtime (safely somehow, if possible).
How can I prevent the component from loading in its constructor and how to display message (exception) from constructor safely at design time and at runtime ?
constructor TSomeComponent.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
if csDesigning in ComponentState then
if SomeIncompatibleCondition then
begin
// how to display message (exception) about the wrong
// condition and interrupt the loading of the component ?
end;
// is it possible to do the same at runtime ?
end;
Thank you
Raise an exception, eg:
constructor TSomeComponent.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
if SomeIncompatibleCondition then
raise Exception.Create('Incompatible condition detected!');
end;
One approach:
Public
Property CreatedOK: boolean read fCreatedOK;
constructor TSomeComponent.Create(AOwner: TComponent);
begin
...
fCreatedOK := ThereIsAnIncompatibleCondition;
end;
Then, the programmer creates the object by:
MyObject := TSomeComponent.Create(Self);
if (NOT MyObject.CreatedOK) then
... deal with it...
We prefer this because it avoids lots of exception code, which can be cumbersome, and a hassle when debugging. (That's another topic though!)
Another approach we use is if the constructor has a lot of work, move the work to another method that the user has to call after constructing. This also has the advantage of letting us pass many values to the object easily.
public
constructor Create...
function InitAfterCreate:boolean;
end;
The caller does:
MyObject := TSomeComponent.Create
if (NOT MyObject.InitAfterCreate) then
... deal with it ...
or, if you're using InitAfterCreate to pass values, you'd define it as
function InitAfterCreate( Value1: Integer, etc.):boolean
Then InitAfterCreate can examine the state of the object and return a result.
One weakness of these approaches is that the programmer has to remember to call the InitAfterCreate or check MyObject.CreatedOk. To protect against them failing to do so, you can put some Asserts in the beginning of some other methods of your object like:
procedure TForm.FormShow
begin
Assert(fCreatedOK, "Programmer failed to check creation result.")
...
end;
In all cases, one challenge is to not terminate the Create leaving the object half-created, in an indeterminate state, which might make it hard for your destructor to know how much to destroy.

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