首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >动态创建的对象(将其类名作为字符串提供)不调用其构造函数

动态创建的对象(将其类名作为字符串提供)不调用其构造函数
EN

Stack Overflow用户
提问于 2017-08-11 12:22:26
回答 2查看 582关注 0票数 1

这是一个对象:

代码语言:javascript
复制
TCell = class(TPersistent)
private
  FAlignmentInCell :byte;
public
  constructor Create; virtual;
published
  property AlignmentInCell:byte  read FAlignmentInCell write FAlignmentInCell;
end;

这是它的构造函数:

代码语言:javascript
复制
constructor TCell.Create;
begin
  inherited;
  FAlignmentInCell:=5;
end;

下面是一个函数,它动态地创建从TPersistent派生的任何对象(参数是作为字符串提供的类名)。

代码语言:javascript
复制
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;

我的想法是创建这样的新单元格(TCell):

代码语言:javascript
复制
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。为什么?有办法解决吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-08-11 12:53:15

这类似于最近的一个问题。

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

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

代码语言:javascript
复制
type
  TCellClass = class of TCell;

现在您可以修改CreateObjectFromClassName以使用这个元类而不是TPersistenClass,然后将调用实际的构造函数。

而且,TempObject从未被释放过。而不是is,我宁愿使用InheritsFrom

我没有测试以下内容,但它应该有效:

代码语言:javascript
复制
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;
票数 5
EN

Stack Overflow用户

发布于 2017-08-11 12:50:49

编译器无法确定您的TPersistentClass类型变量在运行时保存的值。因此,他假定这正是:一个TPersistentClass

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

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

代码语言:javascript
复制
TCell = class(TComponent)
private
  FAlignmentInCell: byte;
public
  constructor Create(AOwner: TComponent); override;
published
  property AlignmentInCell:byte  read FAlignmentInCell write FAlignmentInCell;
end;

您不需要TempObjectCreateObjectFromClassName函数中的所有决策(以及其他人指出的可能的泄漏):

代码语言:javascript
复制
function CreateObjectFromClassName(AClassName:string): TComponent;
var 
  ComponentClass:TComponentClass;
begin
  ComponentClass:=TComponentClass(FindClass(AClassName));
  Result := ComponentClass.Create(nil);  
end;

并确保管理Result的生命周期,因为它没有Owner

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45635147

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档