有什么方法可以在 Delphi 7 中获取旧式 (Borland Pascal) 对象实例的 class 名称?
Is there any way to get the class name of an old style (Borland Pascal) object instance in Delphi 7?
我有很多 class:
的后代
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;
有什么方法可以获取其后代实例的 class 名称吗?我不想为此创建虚拟方法(有成千上万的后代)。
我知道有 typeOf(T)
运算符。但是它的 return 类型是什么?好的。指针。但是我可以投它做什么? PTypeInfo
的转换似乎是错误的。
当我编译此代码并在编译的可执行文件中搜索您的 类 的名称时,没有找到它们。
由此我得出结论,您尝试做的事情是不可能的。
这就是 Delphi 文档中关于对象类型的内容
The Delphi compiler allows an alternative syntax to class types. You
can declare object types using the syntax:
type objectTypeName = object (ancestorObjectType)
memberList
end;
where objectTypeName is any valid identifier, (ancestorObjectType) is
optional, and memberList declares fields, methods, and properties. If
(ancestorObjectType) is omitted, then the new type has no ancestor.
Object types cannot have published members.
Since object types do not descend from System.TObject, they provide no
built-in constructors, destructors, or other methods. You can create
instances of an object type using the New procedure and destroy them
with the Dispose procedure, or you can simply declare variables of an
object type, just as you would with records.
Object types are supported for backward compatibility only. Their use
is not recommended.
所以你的问题的答案是否定的。
您使用的对象类型不包含检索 class 名称的必要方法,因为从 TObject 派生的正常 class 对象确实有。
你现在可以做什么?
您可以修改现有对象,以便添加额外的数据字段,您将在其中存储他们的姓名,然后在需要时读取此姓名。您必须在创建对象时自行设置此值。
或者您可以将所有对象替换为真正的 class 从 TObject 派生出来的对象,这样您就可以自动获得所有 class 功能。这种通常更推荐的方法,即使对象类型在某些情况下可能比 classes 有一些优势。
无法捕获旧样式对象类型名称。
使用TypeOf()
,可以测试对象是否等于一个类型:
if TypeOf(pMA1^) = TypeOf(TMyAncestor) then ...
也可以用来构建lookup-table,以便与实际的类型名匹配。
如果要在这样的 table.
中记录许多对象类型,这可能会有点乏味
在评论中,据说它将用于通过记录基对象期间的名称来捕获内存泄漏 initialization/finalization。
这是一个记录日志的示例,但记录的不是类型名称,而是类型名称地址。它还打印基本对象名称和地址,这对于查明泄漏很有用。对象地址按声明的顺序编号,使用该知识识别泄漏对象应该是相当直接的。
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.
我有很多 class:
的后代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;
有什么方法可以获取其后代实例的 class 名称吗?我不想为此创建虚拟方法(有成千上万的后代)。
我知道有 typeOf(T)
运算符。但是它的 return 类型是什么?好的。指针。但是我可以投它做什么? PTypeInfo
的转换似乎是错误的。
当我编译此代码并在编译的可执行文件中搜索您的 类 的名称时,没有找到它们。
由此我得出结论,您尝试做的事情是不可能的。
这就是 Delphi 文档中关于对象类型的内容
The Delphi compiler allows an alternative syntax to class types. You can declare object types using the syntax:
type objectTypeName = object (ancestorObjectType)
memberList
end;
where objectTypeName is any valid identifier, (ancestorObjectType) is optional, and memberList declares fields, methods, and properties. If (ancestorObjectType) is omitted, then the new type has no ancestor. Object types cannot have published members.
Since object types do not descend from System.TObject, they provide no built-in constructors, destructors, or other methods. You can create instances of an object type using the New procedure and destroy them with the Dispose procedure, or you can simply declare variables of an object type, just as you would with records.
Object types are supported for backward compatibility only. Their use is not recommended.
所以你的问题的答案是否定的。
您使用的对象类型不包含检索 class 名称的必要方法,因为从 TObject 派生的正常 class 对象确实有。
你现在可以做什么?
您可以修改现有对象,以便添加额外的数据字段,您将在其中存储他们的姓名,然后在需要时读取此姓名。您必须在创建对象时自行设置此值。
或者您可以将所有对象替换为真正的 class 从 TObject 派生出来的对象,这样您就可以自动获得所有 class 功能。这种通常更推荐的方法,即使对象类型在某些情况下可能比 classes 有一些优势。
无法捕获旧样式对象类型名称。
使用TypeOf()
,可以测试对象是否等于一个类型:
if TypeOf(pMA1^) = TypeOf(TMyAncestor) then ...
也可以用来构建lookup-table,以便与实际的类型名匹配。 如果要在这样的 table.
中记录许多对象类型,这可能会有点乏味在评论中,据说它将用于通过记录基对象期间的名称来捕获内存泄漏 initialization/finalization。
这是一个记录日志的示例,但记录的不是类型名称,而是类型名称地址。它还打印基本对象名称和地址,这对于查明泄漏很有用。对象地址按声明的顺序编号,使用该知识识别泄漏对象应该是相当直接的。
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.