最近我发现了一段代码,它从一个字符串创建一个TButton实例:'TButton'被用作参数.
我试图将任何对象的已发布属性保存到XML文件(工作正常),最近我想从XML文件中重新创建这些对象.在这个文件中编写了应该创建哪个类(例如TButton),然后是一个属性列表,这些属性应该加载到这个运行时创建的对象中.
上面的示例显示了如何执行此操作的方法,但它不适用于我自己的类.见下面的代码:
TTripple=class (TPersistent)
FFont:TFont;
public
constructor Create;
Destructor Destroy;override;
published
property Font:TFont read FFont write FFont;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TTripple.Create;
begin
inherited;
FFont:=TFont.Create;
end;
destructor TTripple.Destroy;
begin
FFont.Free;
inherited;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterClasses([TButton, TForm, TTripple]);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
CRef : TPersistentClass;
APer : TPersistent;
begin
// CRef := GetClass('TButton');
CRef := GetClass('TTripple');
if CRef<>nil then
begin
APer := TPersistent(TPersistentClass(CRef).Create);
ShowMessage(APer.ClassName); // shows TTripple, what is correct
if APer is TTripple then (APer as TTripple).Font.Color:=90;
/// Here I get error message, because TTriple was not created... ?!?!?!
end;
end;
Run Code Online (Sandbox Code Playgroud)
我无法通过.可能已创建TTripple对象,但未使用其构造函数.
TRipple构造函数未被调用,因为它不是虚拟的.
当您从类引用构造对象时,编译器不知道最终的类类型是什么,因此它无法在代码中分配正确的构造函数.它只知道它是从TPersistent下降的,所以它写出代码来调用TPersistent的构造函数,即TObject.Create.如果你想调用正确的构造函数,你必须虚拟地进行.
已经定义了一个用于从类名中读取类的虚拟构造函数.它在TComponent中定义.使TRipple从TComponent下降并覆盖其虚拟构造函数(将所有者作为参数),然后您的代码将起作用.
您可能不想使用TComponent,还有另一种方法.
添加对您的类的引用
TTrippleClass = class of TTripple;
Run Code Online (Sandbox Code Playgroud)
然后你的按钮点击变为:
procedure TForm1.Button1Click(Sender: TObject);
var
CRef : TTrippleClass;
APer : TPersistent;
begin
CRef := TTrippleClass(GetClass('TTripple'));
if CRef<>nil then
begin
APer := TTripple(TTrippleClass(CRef).Create);
ShowMessage(APer.ClassName); // shows TTripple, what is correct
if APer is TTripple then (APer as TTripple).Font.Color:=90;
end;
end;
Run Code Online (Sandbox Code Playgroud)
现在您可能希望拥有多个Tripple类型,然后创建一个自定义祖先.
TCustomTripple = class(TPersistent)
public
constructor Create;virtual;
end;
TCustomTrippleClass = class of TCustomTripple;
TTripple = class(TCustomTripple)
strict private
fFont : TFont;
public
constructor Create;override;
destructor Destroy;override;
property Font : TFont read fFont;
end;
constructor TCustomTripple.Create;
begin
inherited Create;
end;
constructor TTripple.Create;
begin
inherited;
fFont := TFont.Create;
end;
destructor TTripple.Destroy;
begin
fFont.Free;
inherited;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
CRef : TCustomTrippleClass;
APer : TCustomTripple;
begin
CRef := TCustomTrippleClass(GetClass('TTripple'));
if CRef<>nil then
begin
APer := TCustomTripple(TCustomTrippleClass(CRef).Create);
ShowMessage(APer.ClassName); // shows TTripple, what is correct
if APer is TTripple then (APer as TTripple).Font.Color:=90;
end;
end;
Run Code Online (Sandbox Code Playgroud)