动态创建的对象(提供其类名作为字符串)不调用其构造函数
Dynamically created object (providing its classname as a string) do not call its constructor
这是对象:
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 的对象(参数是 class 作为字符串提供的名称)
function CreateObjectFromClassName(AClassName:string):TPersistent;
var DynamicObject:TPersistent;
TempObject:TPersistent;
DynamicPersistent:TPersistent;
DynamicComponent:TComponent;
PersistentClass:TPersistentclass;
ComponentClass:TComponentClass;
begin
PersistentClass:=TPersistentclass(FindClass(AClassName));
TempObject:=PersistentClass.Create;
if TempObject is TComponent then
begin
ComponentClass:=TComponentClass(FindClass(AClassName));
DynamicObject:=ComponentClass.Create(nil);
end;
if not (TempObject is TComponent) then
begin
DynamicObject:=PersistentClass.Create; // object is really TCell, but appropriate constructor seems to be not called.
end;
result:=DynamicObject;
end;
我的想法是像这样创建新的 Cell (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
类型变量在 运行 时将保持什么值。所以他假设它正是:a TPersistentClass
.
TPersistentClass
定义为 class of TPersistent
。 TPersistent
没有虚构造函数,因此编译器将不会包含在实际 class 的 VMT 中动态查找构造函数地址的调用,而是对唯一的 'hard-coded' 调用匹配的构造函数 TPersistent
具有:它从其基础 class TObject.
继承的构造函数
这可能是一个我不知道的决定,但如果你选择定义 TCell
如下
TCell = class(TComponent)
private
FAlignmentInCell: byte;
public
constructor Create(AOwner: TComponent); override;
published
property AlignmentInCell:byte read FAlignmentInCell write FAlignmentInCell;
end;
您不需要 TempObject
和 CreateObjectFromClassName
函数中的所有决策(以及其他人指出的可能泄漏):
function CreateObjectFromClassName(AClassName:string): TComponent;
var
ComponentClass:TComponentClass;
begin
ComponentClass:=TComponentClass(FindClass(AClassName));
Result := ComponentClass.Create(nil);
end;
并确保管理 Result
的生命周期,因为它没有 Owner
。
这类似于最近的一个问题。
您使用TPersistentClass
。但是TPersistent
没有虚构造函数,所以调用了TPersistent
的普通构造函数,也就是它继承自TObject
的构造函数。
如果要调用虚构造函数,则必须声明一个
type
TCellClass = class of TCell;
现在您可以修改 CreateObjectFromClassName
以使用此元类而不是 TPersistenClass
,然后将调用 actual 构造函数。
此外,TempObject
永远不会被释放。而不是 is
,我宁愿使用 InheritsFrom
.
我没有测试以下内容,但它应该可以工作:
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;
这是对象:
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 的对象(参数是 class 作为字符串提供的名称)
function CreateObjectFromClassName(AClassName:string):TPersistent;
var DynamicObject:TPersistent;
TempObject:TPersistent;
DynamicPersistent:TPersistent;
DynamicComponent:TComponent;
PersistentClass:TPersistentclass;
ComponentClass:TComponentClass;
begin
PersistentClass:=TPersistentclass(FindClass(AClassName));
TempObject:=PersistentClass.Create;
if TempObject is TComponent then
begin
ComponentClass:=TComponentClass(FindClass(AClassName));
DynamicObject:=ComponentClass.Create(nil);
end;
if not (TempObject is TComponent) then
begin
DynamicObject:=PersistentClass.Create; // object is really TCell, but appropriate constructor seems to be not called.
end;
result:=DynamicObject;
end;
我的想法是像这样创建新的 Cell (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
类型变量在 运行 时将保持什么值。所以他假设它正是:a TPersistentClass
.
TPersistentClass
定义为 class of TPersistent
。 TPersistent
没有虚构造函数,因此编译器将不会包含在实际 class 的 VMT 中动态查找构造函数地址的调用,而是对唯一的 'hard-coded' 调用匹配的构造函数 TPersistent
具有:它从其基础 class TObject.
这可能是一个我不知道的决定,但如果你选择定义 TCell
如下
TCell = class(TComponent)
private
FAlignmentInCell: byte;
public
constructor Create(AOwner: TComponent); override;
published
property AlignmentInCell:byte read FAlignmentInCell write FAlignmentInCell;
end;
您不需要 TempObject
和 CreateObjectFromClassName
函数中的所有决策(以及其他人指出的可能泄漏):
function CreateObjectFromClassName(AClassName:string): TComponent;
var
ComponentClass:TComponentClass;
begin
ComponentClass:=TComponentClass(FindClass(AClassName));
Result := ComponentClass.Create(nil);
end;
并确保管理 Result
的生命周期,因为它没有 Owner
。
这类似于最近的一个问题。
您使用TPersistentClass
。但是TPersistent
没有虚构造函数,所以调用了TPersistent
的普通构造函数,也就是它继承自TObject
的构造函数。
如果要调用虚构造函数,则必须声明一个
type
TCellClass = class of TCell;
现在您可以修改 CreateObjectFromClassName
以使用此元类而不是 TPersistenClass
,然后将调用 actual 构造函数。
此外,TempObject
永远不会被释放。而不是 is
,我宁愿使用 InheritsFrom
.
我没有测试以下内容,但它应该可以工作:
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;