The output of the console application below is
Parent
Parent
Parent
instead of
Parent
Child1
Child2
Why would this happen ? Furthermore, how to get the intended output ? Many thanks !
PS: Still no clue after reading this related SO post ...
program Project1;
{$APPTYPE CONSOLE}
type
TParent = class;
TParentClass = class of TParent;
TParent = class
public
ID: string;
constructor Create;
end;
TChild1 = class(TParent)
public
constructor Create;
end;
TChild2 = class(TParent)
public
constructor Create;
end;
constructor TParent.Create;
begin
ID := 'Parent';
end;
constructor TChild1.Create;
begin
ID := 'Child1';
end;
constructor TChild2.Create;
begin
ID := 'Child2';
end;
procedure Test(ImplClass: TParentClass);
var
ImplInstance: TParent;
begin
ImplInstance := ImplClass.Create;
WriteLn(ImplInstance.ID);
ImplInstance.Free;
end;
begin
Test(TParent);
Test(TChild1);
Test(TChild2);
Readln;
end.
Your code behaves the way it does because your constructors are not virtual. Which means that the compiler binds to them at compile time. Which therefore means that the runtime type cannot be taken into account and the code always calls TParent.Create
.
In order to allow the program to bind using the runtime type, you need to use virtual methods and polymorphism. So you can solve your problem by using virtual constructors:
program Project1;
{$APPTYPE CONSOLE}
type
TParent = class;
TParentClass = class of TParent;
TParent = class
public
ID: string;
constructor Create; virtual;
end;
TChild1 = class(TParent)
public
constructor Create; override;
end;
TChild2 = class(TParent)
public
constructor Create; override;
end;
constructor TParent.Create;
begin
ID := 'Parent';
end;
constructor TChild1.Create;
begin
ID := 'Child1';
end;
constructor TChild2.Create;
begin
ID := 'Child2';
end;
procedure Test(ImplClass: TParentClass);
var
ImplInstance: TParent;
begin
ImplInstance := ImplClass.Create;
WriteLn(ImplInstance.ID);
ImplInstance.Free;
end;
begin
Test(TParent);
Test(TChild1);
Test(TChild2);
Readln;
end.
Output
Parent Child1 Child2
A rule of thumb here is that whenever you use a meta-class to instantiate an object, your classes constructor should be virtual. This rule of thumb has exceptions, but I personally have never had to break this rule in my production code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With