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

时间:2017-08-11 12:22:27

标签: 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
  inherited;
  FAlignmentInCell:=5;
end;

这是一个函数,它动态创建从TPersistent派生的任何对象(参数是以字符串形式提供的类名)

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,但我预计为什么?为什么?有办法解决吗?

1 个答案:

答案 0 :(得分:2)

编译器无法确定类型TPersistentClass的变量在运行时将保留的值。所以他假设它正是:TPersistentClass

TPersistentClass被定义为class of TPersistentTPersistent没有虚构造函数,因此编译器不会包含动态查找实际类的VMT中构造函数的地址的调用,而是对唯一匹配构造函数的{硬编码'调用{{ 1}}具有:从它的基类TObject继承的那个。

这可能是我不知道的原因的决定,但如果您选择将TPersistent定义为以下

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