有什么方法可以在Delphi 7中获取旧样式(Borland Pascal)对象实例的类名?

时间:2018-09-06 09:06:19

标签: delphi rtti

我班上有很多后代:

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似乎是错误的。

3 个答案:

答案 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派生的真实类替换所有对象,以便自动添加所有类功能。在某些情况下,即使您的对象类型可能比类都有一些优势,这种通常更推荐的方法。