SOU*_*ser 5 delphi reference class
下面的控制台应用程序的输出是
Parent
Parent
Parent
Run Code Online (Sandbox Code Playgroud)
代替
Parent
Child1
Child2
Run Code Online (Sandbox Code Playgroud)
为什么会这样?此外,如何获得预期的输出?非常感谢 !
PS:看完这篇相关的SO帖后仍然没有线索......
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.
Run Code Online (Sandbox Code Playgroud)
您的代码的行为与它的行为相同,因为构造函数不是虚拟的.这意味着编译器在编译时绑定它们.因此,这意味着不能考虑运行时类型,代码总是调用TParent.Create.
为了允许程序使用运行时类型进行绑定,您需要使用虚方法和多态.因此,您可以使用虚拟构造函数来解决您的问题:
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.
Run Code Online (Sandbox Code Playgroud)
产量
Parent Child1 Child2
这里的经验法则是,无论何时使用元类来实例化对象,您的类构造函数都应该是虚拟的.这个经验法则有例外,但我个人从未在我的生产代码中违反此规则.