使用类引用的多态性和继承?

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)

Dav*_*nan 9

您的代码的行为与它的行为相同,因为构造函数不是虚拟的.这意味着编译器在编译时绑定它们.因此,这意味着不能考虑运行时类型,代码总是调用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

这里的经验法则是,无论何时使用元类来实例化对象,您的类构造函数都应该是虚拟的.这个经验法则有例外,但我个人从未在我的生产代码中违反此规则.