问一个关于元类的问题,请高手们指教(100分)

  • 主题发起人 主题发起人 原子
  • 开始时间 开始时间

原子

Unregistered / Unconfirmed
GUEST, unregistred user!
我对元类的理解不是很到位,有些问题要请教大家。

在一个系统中,我定义了一个关于数据库的基础类,TTabBase,然后数据库中的每张表的记录都定义了一个TTabBase的子类,如职员表Employee,和部门Department表,就定义成
TEmployee = Class(TTabBase);
TDepartment = Class(TTabBase);
这样系统中就有了多个TTabBase的子类。

我想定义一个数组,在不同的地方表示不同的子类列表。
如在处理职员表时,它是
ItemArray: array of TEmployee;
在处理部门表时,它是
ItemArray: array of TDepartment;

现在我的想法是,在一个通用的功能模块中,通过定义一个元类,将子类类型作为变量带进去,从而实现对不同子类的统一操作。

元类的定义和元类变量的定义:
TMetaClass = class of TTabBase;
var
MetaRec: TMetaClass;

这应该没有错吧,但是问题出在使用这个元类的使用上

我把上面的数组定义成
ItemArray: array of MetaRec;

结果出错,Delphi不接受这样的定义(必须是常量或数量类型)

还是如下定义函数也出错,Delphi不接受这样的返回值
function GetClass: MetaRec;

那么,我想请问该如何定义这样的数组和函数?
 
property Items [index : integer] : TTabBase read GetItems write SetItems;
 
ItemArray: array of TTabBase;

function GetClass: TMetaClass;
 
不行啊,两位。

你们讲的这种形式我已经试过了,这样不能调用子类的函数方法和属性。

比如,职员子类定义如下:
type
TEmployee = Class(TTabBase)
private
FName: ShortString;
public
property Name: ShortString read FName write FName;
end;

如果象这样声明:ItemArray: array of TTabBase;
或:Items[Index: Integer]: TTabBase read GetItem write SetItem;

那么ItemArray.Name或Item.Name将无法使用,因为TTabBase类中没有关于Name的声明和定义。

难道除了为每一个子类都声明一个数组外,没有一个通行的办法吗?
 
ItemArray: array of MetaRec定义肯定不对,因为 MetaRec是变量不是类型。
你定义成指针,用强制类型转换来调用对象的成员和方法。
 
两个办法一个是用as或强制类型转换
另外就是
type
TTest = class(TObject)
public
procedure WhoAmI
virtual
abstract;
end;

TTest1 = class(TTest)
public
procedure WhoAmI
override;
end;

TTest2 = class(TTest)
public
procedure WhoAmI
override;
end;

TTestClass = class of TTest;

{ TTest1 }

procedure TTest1.WhoAmI;
begin
ShowMessage('Test1');
end;

{ TTest2 }

procedure TTest2.WhoAmI;
begin
ShowMessage('Test2');
end;

procedure TForm7.Button1Click(Sender: TObject);
var
Item : array of TTest;
I : Integer;
begin
SetLength(Item, 2);
Item[0] := TTest1.Create;
Item[1] := TTest2.Create;

for I := Low(Item) to High(Item) do
begin
Item.WhoAmI;
Item.Free;
end;
end;
 
谢谢各位,我现在的确是用强制类型转换解决的。
但是这样离我的原来的设想还有一定的差别。按我的想法,是用一个通用的过程处理所有的子类。在编程期间是不需要知道处理子类的具体类型,而是在程序运行期间把具体的子类类型作为参数传入。类似于以下:

type
TMetaClass: class of TTabBase;
TEmployee = class(TTabBase)
...
end;

procedure Test(SonClass: TMetaClass)
begin
ShowMessage(SonClass(Items[Index]).Name)
//这一句不起作用
end;

然后象这样调用:
var
MetaRec: TMetaClass;
begin
MetaRec := TEmployee;
Test(MetaRec)
//我以为这样可以把子类类型传过去,其实传过去的还是TTabBase
end;

上面的程序,虽然编译不出错,但是也达不到我预想的效果,主要是传过去的MetaRec依然被认为TTabBase,而不是TEmployee。
 
(aTabBase as TEmployee).来访问子类的属性,函数等待
 
type
TTest = class(TObject)
public
procedure WhoAmI
virtual
abstract;
end;

TTest1 = class(TTest)
public
procedure WhoAmI
override;
end;

TTest2 = class(TTest)
public
procedure WhoAmI
override;
end;

TTestClass = class of TTest;

{ TTest1 }

procedure TTest1.WhoAmI;
begin
ShowMessage('Test1');
end;

{ TTest2 }

procedure TTest2.WhoAmI;
begin
ShowMessage('Test2');
end;

procedure Test(T: TTest);
begin
ShowMessage(T.ClassName);
end;

function CreateIt(T: TTestClass): TTest;
begin
Result := T.Create;
end;

procedure TForm7.Button1Click(Sender: TObject);
var
Item : array of TTest;
I : Integer;
begin
SetLength(Item, 2);
Item[0] := CreateIt(TTest1);
Item[1] := CreateIt(TTest2);

for I := Low(Item) to High(Item) do
begin
Test(Item);
Item.Free;
end;
end;
 
谢谢,受教了
 
后退
顶部