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的所有后代都是由它们自己的构造函数创建的。我会检查你的建议,修正一些小瑕疵。。。塔克斯