mjn*_*mjn 20 delphi constructor reference class delphi-2009
如何使用类引用创建对象的实例,并确保执行构造函数?
在此代码示例中,将不会调用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;
Run Code Online (Sandbox Code Playgroud)
Ale*_*lex 26
用这个:
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;
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用类型转换为TMyClass(而不是"TMyClass类").
小智 22
亚历山大的解决方案很好,但在某些情况下还不够.假设您希望设置一个TClassFactory类,其中TClass引用可以在运行时存储,并且可以在以后检索任意数量的实例.
这样的类工厂永远不会知道它所拥有的类的实际类型,因此不能将它们转换为它们的相应元类.要在这种情况下调用正确的构造函数,以下方法将起作用.
首先,我们需要一个简单的演示类(不介意公共字段,它仅用于演示目的).
interface
uses
RTTI;
type
THuman = class(TObject)
public
Name: string;
Age: Integer;
constructor Create(); virtual;
end;
implementation
constructor THuman.Create();
begin
Name:= 'John Doe';
Age:= -1;
end;
Run Code Online (Sandbox Code Playgroud)
现在我们纯粹通过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;
Run Code Online (Sandbox Code Playgroud)
你会发现对象"human1"和"human2"已被初始化为零,即Name =''和Age = 0,这不是我们想要的.对象human3改为保存THuman构造函数中提供的默认值.
但请注意,此方法要求您的类具有不带参数的构造方法.以上所有内容都不是由我构思出来的,而是在Rob Love的技术角中更加精细地解释(例如,c.免费部分).
您的代码略有修改:
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;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
37860 次 |
| 最近记录: |