如何从类引用创建Delphi对象并确保构造函数执行?
如何使用类引用创建对象的实例,以及 确保构造函数已执行 在此代码示例中,不会调用TMyClass的构造函数:如何从类引用创建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;
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;