如何从类引用创建Delphi对象并确保构造函数执行?

如何从类引用创建Delphi对象并确保构造函数执行?,delphi,class,constructor,reference,delphi-2009,Delphi,Class,Constructor,Reference,Delphi 2009,如何使用类引用创建对象的实例,以及 确保构造函数已执行 在此代码示例中,不会调用TMyClass的构造函数: type TMyClass = class(TObject) MyStrings: TStrings; constructor Create; virtual; end; constructor TMyClass.Create; begin MyStrings := TStringList.Create; end; procedure Test;

如何使用类引用创建对象的实例,以及 确保构造函数已执行

在此代码示例中,不会调用TMyClass的构造函数:

type
   TMyClass = class(TObject)
     MyStrings: TStrings;
     constructor Create; virtual;
   end;

constructor TMyClass.Create;
begin
   MyStrings := TStringList.Create;
end;

procedure Test;
var
   Clazz: TClass;
   Instance: TObject;
begin
   Clazz := TMyClass;
   Instance := Clazz.Create;
end;

您的代码稍有修改:

type
  TMyObject = class(TObject)
    MyStrings: TStrings;
    constructor Create; virtual;
  end;
  TMyClass = class of TMyObject;

constructor TMyObject.Create;
begin
  inherited Create;
  MyStrings := TStringList.Create;
end;

procedure Test; 
var
  C: TMyClass;
  Instance: TObject;
begin
   C := TMyObject;
   Instance := C.Create;
end;
使用以下命令:

type
  TMyClass = class(TObject)
    MyStrings: TStrings;
    constructor Create; virtual;
  end;
  TMyClassClass = class of TMyClass; // <- add this definition

constructor TMyClass.Create;
begin
   MyStrings := TStringList.Create;
end;

procedure Test;
var
  Clazz: TMyClassClass; // <- change TClass to TMyClassClass
  Instance: TObject;
begin
   Clazz := TMyClass; // <- you can use TMyClass or any of its child classes. 
   Instance := Clazz.Create; // <- virtual constructor will be used
end;
类型
TMyClass=类(TObject)
MyStrings:TStrings;
构造函数创建;事实上的
结束;

TMyClassClass=TMyClass的类;// 请检查是否可以选择覆盖后构造。

Alexander的解决方案很好,但在某些情况下并不足够。假设您希望设置一个TClassFactory类,在该类中可以在运行时存储TClass引用,并在以后检索任意数量的实例

这样的类工厂永远不会知道它所持有的类的实际类型,因此无法将它们转换为相应的元类。要在这种情况下调用正确的构造函数,以下方法将起作用

首先,我们需要一个简单的demo类(不要介意公共字段,它只是用于演示目的)

现在我们纯粹通过RTTI和正确的构造函数调用实例化THuman类型的对象

procedure CreateInstance();
var
  someclass: TClass;
  c: TRttiContext;
  t: TRttiType;
  v: TValue;
  human1, human2, human3: THuman;
begin
  someclass:= THuman;

  // Invoke RTTI
  c:= TRttiContext.Create;
  t:= c.GetType(someclass);

  // Variant 1a - instantiates a THuman object but calls constructor of TObject
  human1:= t.AsInstance.MetaclassType.Create;

  // Variant 1b - same result as 1a
  human2:= THuman(someclass.Create);

  // Variant 2 - works fine
  v:= t.GetMethod('Create').Invoke(t.AsInstance.MetaclassType,[]);
  human3:= THuman(v.AsObject);

  // free RttiContext record (see text below) and the rest
  c.Free;

  human1.Destroy;
  human2.Destroy;
  human3.Destroy;
end;
您将发现对象“human1”和“human2”已初始化为零,即Name=''和Age=0,这不是我们想要的。对象human3保留THuman构造函数中提供的默认值


但是,请注意,此方法要求类具有不带参数的构造函数方法。所有这些都不是我构思的,而是在中进行了精辟而详细的解释(例如,c.Free部分)。

您可以在基类中创建一个抽象方法,并在构造函数中调用它,在从类引用创建时重写要执行的子类。

Ok,如果我理解正确,这意味着如果我想用Delphi构建一个通用对象工厂,我需要给一个变量分配“类的TMyClass”——但这似乎是不可能的。如果你想构造某种类型的对象,那么你需要有类的类型信息。如果没有类信息,则无法构造此类型的对象。很明显;)非常好的主意,它是TObject中的一个虚拟方法,所以我不需要添加任何合成的新根类+1这个想法。这并不是问题所要求的。我遇到了同样的问题,当我在某个列表管理器的构造函数中传递类引用,指定它填充列表的子类的类型,并且当列表创建子类时,只调用子构造函数的父基类。。。儿童用品的制造商不是。。。因为构造函数必须有参数,所以对我来说唯一的解决方案是声明一个抽象方法,在父构造函数中调用它,并在子类中重写。这个解决方法可能会帮助面临同样问题的人。。。顺致敬意,
procedure CreateInstance();
var
  someclass: TClass;
  c: TRttiContext;
  t: TRttiType;
  v: TValue;
  human1, human2, human3: THuman;
begin
  someclass:= THuman;

  // Invoke RTTI
  c:= TRttiContext.Create;
  t:= c.GetType(someclass);

  // Variant 1a - instantiates a THuman object but calls constructor of TObject
  human1:= t.AsInstance.MetaclassType.Create;

  // Variant 1b - same result as 1a
  human2:= THuman(someclass.Create);

  // Variant 2 - works fine
  v:= t.GetMethod('Create').Invoke(t.AsInstance.MetaclassType,[]);
  human3:= THuman(v.AsObject);

  // free RttiContext record (see text below) and the rest
  c.Free;

  human1.Destroy;
  human2.Destroy;
  human3.Destroy;
end;