Delphi 动态创建的对象(以字符串形式提供其类名)不调用其构造函数

Delphi 动态创建的对象(以字符串形式提供其类名)不调用其构造函数,delphi,delphi-7,Delphi,Delphi 7,以下是对象: TCell = class(TPersistent) private FAlignmentInCell :byte; public constructor Create; virtual; published property AlignmentInCell:byte read FAlignmentInCell write FAlignmentInCell; end; 这是它的构造器: constructor TCell.Create; begin inheri

以下是对象:

TCell = class(TPersistent)
private
  FAlignmentInCell :byte;
public
  constructor Create; virtual;
published
  property AlignmentInCell:byte  read FAlignmentInCell write FAlignmentInCell;
end;
这是它的构造器:

constructor TCell.Create;
begin
  inherited;
  FAlignmentInCell:=5;
end;
下面是一个函数,它动态创建从TPersistent派生的任何对象(参数是作为字符串提供的类名)

我的想法是创建如下的新单元(TCell):

procedure TForm1.btn1Click(Sender: TObject);
var p:TPersistent;
begin
  p := CreateObjectFromClassName('TCell');
  ShowMessage(IntToStr(TCell(p).AlignmentInCell)); // it is 0. (Why?)
end;

当我想检查AlignmentInCell属性时,我得到了0,但我希望是5。为什么?有办法修复它吗?

编译器无法确定
TPersistentClass类型的变量在运行时将保持什么值。所以他假设它确实是:一个
TPersistentClass

TPersistentClass
被定义为TPersistent的
TPersistent
没有虚拟构造函数,因此编译器将不包括在实际类的VMT中动态查找构造函数地址的调用,而是对唯一匹配构造函数
TPersistent
的“硬编码”调用:它从基类ToObject继承的构造函数

这可能是一个决定,原因我不知道,但如果您选择如下定义
TCell

TCell = class(TComponent)
private
  FAlignmentInCell: byte;
public
  constructor Create(AOwner: TComponent); override;
published
  property AlignmentInCell:byte  read FAlignmentInCell write FAlignmentInCell;
end;
您不需要
TempObject
CreateObjectFromClassName
函数中的所有决策(以及其他人指出的可能泄漏):


并确保管理
结果
的生存期,因为它没有
所有者

编译器无法确定
TPersistentClass类型的变量在运行时将保持什么值。所以他假设它确实是:一个
TPersistentClass

TPersistentClass
被定义为TPersistent的
TPersistent
没有虚拟构造函数,因此编译器将不包括在实际类的VMT中动态查找构造函数地址的调用,而是对唯一匹配构造函数
TPersistent
的“硬编码”调用:它从基类ToObject继承的构造函数

这可能是一个决定,原因我不知道,但如果您选择如下定义
TCell

TCell = class(TComponent)
private
  FAlignmentInCell: byte;
public
  constructor Create(AOwner: TComponent); override;
published
  property AlignmentInCell:byte  read FAlignmentInCell write FAlignmentInCell;
end;
您不需要
TempObject
CreateObjectFromClassName
函数中的所有决策(以及其他人指出的可能泄漏):


并确保管理
结果
的生命周期,因为它没有
所有者

这与最近的问题类似

您可以使用
TPersistentClass
。但是
TPersistent
没有虚拟构造函数,因此调用
TPersistent
的普通构造函数,即它从
TObject
继承的构造函数

如果要调用虚拟构造函数,必须声明

type
  TCellClass = class of TCell;
现在您可以修改
CreateObjectFromClassName
来使用这个元类而不是
tpersistenceClass
,然后将调用实际的构造函数

而且,
TempObject
永远不会被释放。我宁愿使用
InheritsFrom
,而不是
is

我没有测试以下内容,但它应该可以工作:

function CreateObjectFromClassName(const AClassName: string; AOwner: TComponent): TPersistent;
var 
  PersistentClass: TPersistentclass;
begin
  PersistentClass := FindClass(AClassName);
  if PersistentClass.InheritsFrom(TComponent) then
    Result := TComponentClass(PersistentClass).Create(AOwner)
  else if PersistentClass.InheritsFrom(TCell) then
    Result := TCellClass(PersistentClass).Create
  else
    Result := PersistentClass.Create;
end;

这类似于最近的一个问题

您可以使用
TPersistentClass
。但是
TPersistent
没有虚拟构造函数,因此调用
TPersistent
的普通构造函数,即它从
TObject
继承的构造函数

如果要调用虚拟构造函数,必须声明

type
  TCellClass = class of TCell;
现在您可以修改
CreateObjectFromClassName
来使用这个元类而不是
tpersistenceClass
,然后将调用实际的构造函数

而且,
TempObject
永远不会被释放。我宁愿使用
InheritsFrom
,而不是
is

我没有测试以下内容,但它应该可以工作:

function CreateObjectFromClassName(const AClassName: string; AOwner: TComponent): TPersistent;
var 
  PersistentClass: TPersistentclass;
begin
  PersistentClass := FindClass(AClassName);
  if PersistentClass.InheritsFrom(TComponent) then
    Result := TComponentClass(PersistentClass).Create(AOwner)
  else if PersistentClass.InheritsFrom(TCell) then
    Result := TCellClass(PersistentClass).Create
  else
    Result := PersistentClass.Create;
end;

您可以通过调试来验证您的假设<调用的是code>TObject.Create
,而不是
TCell.Create
。您可以通过调试来验证您的假设<调用的是code>TObject.Create
,而不是
TCell.Create
。是的,我确实定义了TCellClass=TCell的类;并显式地调用它DynamicObject:=TCellClass(FindClass(AClassName)).Create;实际上,TCell的所有后代都是由它们自己的构造函数创建的。我会检查你的建议,修正一些小瑕疵。。。ThanxYes,我真的定义了TCellClass=TCell的类;并显式地调用它DynamicObject:=TCellClass(FindClass(AClassName)).Create;实际上,TCell的所有后代都是由它们自己的构造函数创建的。我会检查你的建议,修正一些小瑕疵。。。塔克斯