我班上有很多后代:
PMyAncestor =^TMyAncestor;
TMyAncestor = object
public
constructor init;
destructor done; virtual;
// There are virtual methods as well
end;
PMyDescendant1 =^TMyDescendant1;
TMyDescendant1 = object ( TMyAncestor )
end;
PMyDescendant2 =^TMyDescendant2;
TMyDescendant2 = object ( TMyAncestor )
end;
PMyDescendant3 =^TMyDescendant3;
TMyDescendant3 = object ( TMyDescendant2 )
end;
procedure foo;
var
pMA1, pMA2, pMA3, pMA4 : PMyAncestor;
s : string;
begin
pMA1 := new( PMyAncestor, init );
pMA2 := new( PMyDescendant1, init );
pMA3 := new( PMyDescendant2, init );
pMA4 := new( PMyDescendant3, init );
try
s := some_magic( pMA1 ); // s := "TMyAncestor"
s := some_magic( pMA2 ); // s := "TMyDescendant1"
s := some_magic( pMA3 ); // s := "TMyDescendant2"
s := some_magic( pMA4 ); // s := "TMyDescendant3"
finally
dispose( pMA4, done );
dispose( pMA3, done );
dispose( pMA2, done );
dispose( pMA1, done );
end;
end;
有没有办法获取其后代实例的类名?由于这个原因,我不想创建虚拟方法(有成千上万的后代)。
我知道这里有typeOf(T)
运算符。但是它的返回类型是什么?好。指针。但是,我可以为它投些什么呢?投射到PTypeInfo
似乎是错误的。
答案 0 :(得分:5)
当我编译此代码并在已编译的可执行文件中搜索您的类的名称时,找不到它们。
由此我得出结论,您要尝试做的事是不可能的。
答案 1 :(得分:4)
不可能捕获旧的对象类型名称。
使用TypeOf()
,可以测试对象是否等于类型:
if TypeOf(pMA1^) = TypeOf(TMyAncestor) then ...
它也可以用来建立查找表,以与实际的类型名称匹配。 如果要在此类表中记录许多对象类型,这可能会有些乏味。
在评论中,据说它将通过在基础对象初始化/完成期间记录名称来捕获内存泄漏。
这是一个进行日志记录的示例,但不是类型名称,而是logg类型名称地址。它还会打印基础对象名称和地址,这对于查明泄漏很有用。对象地址按声明的顺序编号,并且应该很简单地用该知识来识别泄漏的对象。
program Project121;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
Type
PMyAncestor =^TMyAncestor;
TMyAncestor = object
public
constructor init;
destructor done; virtual;
// There are virtual methods as well
end;
PMyDescendant1 =^TMyDescendant1;
TMyDescendant1 = object ( TMyAncestor )
end;
PMyDescendant2 =^TMyDescendant2;
TMyDescendant2 = object ( TMyAncestor )
end;
PMyDescendant3 =^TMyDescendant3;
TMyDescendant3 = object ( TMyDescendant2 )
end;
constructor TMyAncestor.init;
begin
{$IFDEF DEBUG}
WriteLn( IntToHex(Integer(TypeOf(Self))),
' Base class - TMyAncestor:',
IntToHex(Integer(TypeOf(TMyAncestor))));
{$ENDIF}
end;
destructor TMyAncestor.done;
begin
{$IFDEF DEBUG}
WriteLn(IntToHex(Integer(TypeOf(Self))),' Done.');
{$ENDIF}
end;
procedure foo;
var
pMA1, pMA2, pMA3, pMA4 : PMyAncestor;
s : string;
begin
pMA1 := new( PMyAncestor, init );
pMA2 := new( PMyDescendant1, init );
pMA3 := new( PMyDescendant2, init );
pMA4 := new( PMyDescendant3, init );
try
(*
Do something
*)
finally
dispose( pMA4, done );
dispose( pMA3, done );
dispose( pMA2, done );
dispose( pMA1, done );
end;
end;
begin
foo;
ReadLn;
end.
输出:
0041AD98 Base class - TMyAncestor:0041AD98
0041ADA8 Base class - TMyAncestor:0041AD98
0041ADB8 Base class - TMyAncestor:0041AD98
0041ADC8 Base class - TMyAncestor:0041AD98
0041ADC8 Done.
0041ADB8 Done.
0041ADA8 Done.
0041AD98 Done.
答案 2 :(得分:0)
这是Delphi文档中有关对象类型的内容
Delphi编译器允许使用类类型的替代语法。您 可以使用以下语法声明对象类型:
type objectTypeName = object (ancestorObjectType)
memberList
end;
其中objectTypeName是任何有效标识符,(ancestorObjectType)是 可选,memberList声明字段,方法和属性。如果 (ancestorObjectType)被省略,则新类型没有祖先。 对象类型不能具有已发布的成员。
由于对象类型不是从System.TObject派生的,因此它们不提供 内置的构造函数,析构函数或其他方法。您可以创建 使用New过程的对象类型实例并销毁它们 使用Dispose过程,或者您可以简单地声明一个变量 对象类型,就像处理记录一样。
仅出于向后兼容的目的而支持对象类型。他们的使用 不推荐。
所以您的问题的答案为否。
您使用的对象类型不包含检索类名的必要方法,就像从TObject派生的普通类一样。
您现在可以做什么?
您可以修改现有对象,以便添加其他数据字段,在其中存储其名称,然后在需要时读取该名称。您必须在创建对象时自行设置此值。
或者您可以用TObject派生的真实类替换所有对象,以便自动添加所有类功能。在某些情况下,即使您的对象类型可能比类都有一些优势,这种通常更推荐的方法。