Delphi 如何从提供类名的字符串创建实例?

Delphi 如何从提供类名的字符串创建实例?,delphi,Delphi,最近我发现了一段代码,它从字符串创建了一个TButton实例:“TButton”被用作参数 看 我试图将任何对象的已发布属性保存到XML文件中(工作正常),最近我想从XML文件中重新创建这些对象。在该文件中,将写入应该创建的类(例如TButton),然后遵循属性列表,这些属性应加载到此运行时创建的对象中 上面的例子展示了如何做到这一点,但它不适用于我自己的类。见下面的代码: TTripple=class (TPersistent) FFont:TFont; public

最近我发现了一段代码,它从字符串创建了一个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;
TTripple=class(TPersistent)
FFont:TFont;
公众的
构造函数创建;
毁灭者毁灭;推翻
出版
属性字体:TFont read-FFont-write-FFont;
结束;
变量
表1:TForm1;
实施
{$R*.dfm}
构造函数。创建;
开始
继承;
FFont:=TFont.Create;
结束;
析构函数TTripple.Destroy;
开始
免费的;
继承;
结束;
过程TForm1.FormCreate(发送方:TObject);
开始
寄存器类([TButton,TForm,TTripple]);
结束;
程序TForm1.按钮1单击(发送方:TObject);
变量
CRef:TPE类;
纸张:持久性;
开始
//CRef:=GetClass('TButton');
CRef:=GetClass('TTripple');
如果是CRefnil那么
开始
纸张:=TPersistent(TPersistentClass(CRef).Create);
ShowMessage(文件类名称);//显示TTripple,什么是正确的
如果纸张为TTripple,则(纸张为TTripple)。字体颜色:=90;
///在这里我得到错误消息,因为TTriple没有被创建?!?!?!
结束;
结束;

我打不通。TTripple对象可能已创建,但未使用其构造函数。

未调用TRipple构造函数,因为它不是虚拟的

当您从类引用构造对象时,编译器还不知道最终的类类型是什么,因此无法在代码中指定正确的构造函数。它只知道它是从TPersistent降下来的,所以它编写代码来调用TPersistent的构造函数,即TObject.Create。如果你想调用正确的构造函数,你必须虚拟地去做


已经定义了一个虚拟构造函数,用于从类名读取类。它在TComponent中定义。让TRipple从TComponent下降并重写其虚拟构造函数(以所有者为参数的构造函数),然后代码就可以运行了。

您可能不想使用TComponent,还有另一种方法

添加对类的引用

TTrippleClass = class of TTripple;
然后,您的按钮单击变成:

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;
procedure TForm1.按钮1点击(发送方:TObject);
变量
CRef:tteclass;
纸张:持久性;
开始
CRef:=TTrippleClass(GetClass('TTripple');
如果是CRefnil那么
开始
纸张:=TTripple(TTrippleClass(CRef).Create);
ShowMessage(文件类名称);//显示TTripple,什么是正确的
如果纸张为TTripple,则(纸张为TTripple)。字体颜色:=90;
结束;
结束;
现在,您可能希望拥有多个Triple类型,然后创建一个自定义祖先

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;
tcustomtriple=class(TPersistent)
公众的
构造函数创建;事实上的
结束;
TCustomTrippleClass=TCustomTripple的类;
TTripple=类(TCustomTripple)
严格保密
fFont:TFont;
公众的
构造函数创建;推翻
毁灭者毁灭;推翻
属性字体:TFont read fFont;
结束;
构造函数tcustomtriple.Create;
开始
继承创造;
结束;
构造函数。创建;
开始
继承;
fFont:=TFont.Create;
结束;
析构函数TTripple.Destroy;
开始
免费的;
继承;
结束;
程序TForm1.按钮1单击(发送方:TObject);
变量
CRef:TCustomTrippleClass;
纸张:tCustomTriple;
开始
CRef:=TCustomTrippleClass(GetClass('TTripple');
如果是CRefnil那么
开始
APer:=TCustomTripple(TCustomTrippleClass(CRef).Create);
ShowMessage(文件类名称);//显示TTripple,什么是正确的
如果纸张为TTripple,则(纸张为TTripple)。字体颜色:=90;
结束;
结束;

您是否尝试编译此文件?它不起作用,因为TCustomTripple的双重声明(作为'TPersistent'和'class of TCustomTripple')。我这样做了,但后来复制了它(手动),因为我在另一台机器上使用Delphi,将答案发布到了另一台机器上。我来查一下。谢谢,肯,你的第一个例子很好用。我很感激。第二次我没能做到——正如你所说的那样。对于我的puropose来说,Mason的答案足以证明(至少在第一个示例中)构造函数不需要是虚拟的。