如何根据类的名字创建一个类实例(200分)

  • 主题发起人 主题发起人 drizzledu
  • 开始时间 开始时间
D

drizzledu

Unregistered / Unconfirmed
GUEST, unregistred user!
我建了一系列的类,
T1,T2,T3,T4,T5,T6.........
他们都有一个共同的父类T0,(注明: T0是从线程类继承来的)
我现在要根据他们的名字创建这些对象, 我现在是这样处理的

function GetObj(Aname: string): T0;
begin
if Aname = 'T1' then Result := T1.create()
else if Aname = 'T2' then Result := T2.create()
else if Aname = 'T3' then Result := T3.create()
else if Aname = 'T4' then Result := T4.create()
else if Aname = 'T5' then Result := T5.create()
else if Aname = 'T6' then Result := T6.create();
.
.
.
.
.
.
end;

我想要一种简单的方法
function GetObj(Aname: string): T0;
begin
Result := GetClass(Aname).Create;
end;
 
用数组存他们的名字
 
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;

type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses Types;

{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject);
var
Form: TForm;
begin
Application.CreateForm(TComponentClass(FindClass('TForm1')), Form);
Form.ShowModal;

end;
initialization
RegisterClass(TForm1);

end.
 
type
TAclass=class(TComponet)
public
TAMetaClass=class of TAClass;
end;
type
TBClass=Class(TAClass)
initiliazation
RegisterClass(TAClass)
end;
-------------
Your ClassName put in the TList;
-------------
function (TypeName:String):TAClass;
var
Aclass:TAMetaClass;
begin
AClass=TAMetaClass(GetClass(TypeName));
if AClass<>nil then
Result:=Aclass.create(nil);
end;
 
就像 hfghfghfg 說的那樣,先用
initialization
RegisterClass(TForm1);

注冊一下,再用findclass 找出來就可以了!
 
感谢几位富翁的回答, 但我漏了说, 我的类都是从线程类派生出来的, 故以上方法都无效
 
TBaseClass = class of TBase;
TA = class(TBase)
TB = class(TA); //或者是TBase的任何子类,
那么只要是从TBase继承下来的,创建的时候,可使用
function GetObj(class: TBaseClass): TBase;
begin
result := class.create;
end;
调用
getObj(TA);
getObj(TB);
 
虽然和你说的用名字获得实例,但是你看是否可以变通下不传名字,如果需要传名字获得类名,这些类是必须从TPersistent类继承下来的
 
TBaseClass = class of TBase;
TA = class(TBase)
TB = class(TA); //或者是TBase的任何子类,
那么只要是从TBase继承下来的,创建的时候,可使用
function GetObj(class: TBaseClass): TBase;
begin
Result := class.NewInterface;
Result.Create();
end;
调用
getObj(TA);
getObj(TB);
 
上面的方法其实不必用到类工厂模式了, 直接 Txx.Create;
也许hanpengshan_00说得对, 非TPersistent派生类无法从类名字得到实例,
再等几天再散分, 谢谢各位富翁
 
RegisterClass(XX);
然后
FindClass(XX).create 这样不行吗?

如果不行的话,就只能自己实现了,
重载create过程,加入一个类名参数。
在create里面调用tobject的ClassNameIs函数来比较传入的类名参数,是就创建,否就退出。

在单元初始化时把所有这些类的create地址保存到一个tlist

在GetObj函数里面直接循环调用tlist里面的函数入口就行了。
(以下代码在浏览器里打的,未经验证。)
var
i: integer;
fun1: function create1(const s: string): pointer;
begin
for i:= 0 to list.count-1 do
begin
fun1:= list;
if fun1<> nil then
begin
result:=fun1('类名');
if result<> nil then
exit; //result 里面保存的就是创建好的类实例了。
end;
end;
end;
 
根据类名字符串找到类变量可先RegisterClass再用FindClass来查找。但根据类变量(而不是具体)创建类实例不能直接用Create方法,得用NewInstance再Create,具体可参考TApplicaiton的CreateForm方法的源码。
 
不知道楼上说的类变量是什么?如果只是一个申明了的变量,没初始化时是无效的指针,什么也做不了。
前面我说的create构造方法是类方法,属于静态方法。它的地址是编译时就确定的。
不需实例即可调用。类的create构造方法会调用tobject的NewInstance来分配内存。
然后再会自动调用对象继承的create代码来做进一部的工作。
所以楼上所说的“NewInstance再Create”已经属于对象一级的。和类静态方法create虽同名但有区别。

下面一创建实例的内容摘抄自insead vcl,两段代码效果等同。
var
abobj: tbase;
aobj: tobject;
begin
代码一:
abobj:= tbase.craete;
代码二,先newInstance再create,效果等同于代码一:
aobj:= tobject(tbase.newInstance);
abobj:= tbase(aobj.create);
end;
 
后退
顶部