【问题标题】:How to get the class name of a polymorph C++ Object using WIN32 Debug Info API?如何使用 WIN32 调试信息 API 获取多态 C++ 对象的类名?
【发布时间】:2021-07-29 08:00:06
【问题描述】:

win32 调试器在检查器窗口中显示有问题的类名,这意味着信息必须可用,只有微软开发人员公开该功能才有问题。

出于调试/诊断/开发目的我想编写一个函数来获取 c++ 对象的实例化类名作为输出,并将指向基类的指针作为输入。

例如:

const char* GetNameOfInstanciatedClassByBaseClassPtr(class B* pBaseClassOrInstanciatedClass);

class B { public: virtual void Init (){
  assert(StringIsEqual(GetNameOfInstanciatedClassByBaseClassPtr(this), "C")); } };
class C : B {} c; c.Init(); 

所以请提供一个实现函数GetNameOfInstanciatedClassByBaseClassPtr的解决方案。

所以问题是:所需的 lib/header/function 是什么?我想一个用于 win32 调试信息的 API 会有所帮助吗?

在我的情况下,编写返回字符串或 type_info 的虚函数不是可接受的解决方案。

正如我之前所说:这仅用于诊断/调试/开发目的,不适用于生产代码,因此请避免讨论干净的代码目的。我也可以手动收集信息,但因为它大约有 260 个课程,所以我可能会更快。 ;)

编辑:在问题的第一个版本中,我在基类的构造函数中调用了函数“GetNameOfInstanciatedClassByBaseClassPtr”,但我观察到该信息在构造函数时尚不可用。所以我把它放在一个总是被调用的 Init 方法中。在此方法中,调试器显示实例化类的名称,因此如果我将对函数 GetNameOfInstanciatedClassByBaseClassPtr 的调用放入我的 init 方法中,则可以获得信息。 rtti-typeinfo 似乎也是如此。

编辑2: 如前所述,它可能不适用于 void*,您可能需要 B* 类。但是,这很容易测试。请注意,有些事情可能是编译器特定的。所以我再次调整了这个问题。

所以我从 cmets 得到的答案是使用任一

  • 运行时类型信息 (rtti)(通过原生 c++) [1]
  • Microsoft 调试接口访问 SDK(通过 COM) [2]

[1] 您需要在文件或项目的编译器设置中启用此功能。

[2] 那是更复杂的解决方案。

【问题讨论】:

  • “win32 调试器在检查器窗口中显示有问题的类名”来自void* 或来自B*
  • 调试器使用 pdb 文件。获取指向虚拟表的指针。看看这个地址是哪个符号名称。解析名称。等等。这一切都不是简单的
  • 此信息由链接器发送到程序数据库 (PDB) 文件中。您可以使用Debug Interface Access SDK从那里查询信息。
  • @Jarod42:很好,这绝对不是 void*,它是一个类*。另外我认为 typeinfo 可能在我的情况下工作,当然不是在构造函数内部,在子类未初始化的地方......
  • @IInspectable:非常有价值,谢谢。这是我发现 typeinfo 不起作用后的第一种方法。但正如我所说,我认为它不能在 C++ 中子类的基类构造函数中工作。我认为它可以通过调试接口访问 sdk 以及 typeinfo 来完成,至少在对象完全构造后调用的函数内部。

标签: c++ winapi reflection debug-information


【解决方案1】:

你可以使用typeid:

#include <iostream>
#include <typeinfo>

struct A {
    virtual void printName(){
        std::cout << typeid(*this).name() << "\n";
    }
    virtual ~A() = default;
};
struct C : A{};

int main() {
    C c;
    c.printName();
    A a;
    a.printName();
}

但是,名称是由实现定义的。 Possible output is:

1C
1A

并且您无法从void* 中获取对象动态类型的typeid。看到这个有点相关的问题:How to get the typeid of a void* pointer?

还有(来自cppreference

如果 typeid 用于正在构造或销毁的对象(在析构函数或构造函数中,包括构造函数的初始化列表或默认成员初始化程序),则此 typeid 引用的 std::type_info 对象表示类即使它不是派生最多的类,也会被构造或销毁。

也就是说,不能使用typeid 来推断构造函数(或析构函数)中的动态类型。我知道在构造函数或析构函数中获取动态类型的唯一方法是dynamic_cast,但您需要事先知道类型。

【讨论】:

  • 谢谢。我试过了,它只是返回了基类的名称。我启用了 rtti 编译器选项,让它像这样工作。 win32 中是否有额外的选项让它返回子类名?
  • @seebee 不确定您的意思。 1CC 的名称
  • 是的,但您说取决于实现(编译器的?!)它也可能返回 1A(A 的名称)。就我而言,这发生了,但这并不能解决问题,因为我需要“密封”/“实例化”类“C”/“1C”的名称。我在问微软是否实现了编译器开关来控制这种行为(返回 1A 或 1C)
  • @seebee 名称是每个类的实现定义。即输出也可以是CCC AAA。不同的类有不同的名字
  • 当然,生成的类名将代表代码中使用的实际标识符,这是毫无疑问的。问题是,子类的信息是否在基类构造函数中可用。对于 rtti 和调试信息,这似乎失败了。因此,对于 ChildClass 类,如果您在类 BaseClass 的构造函数中调用 GetTypeInfo,结果将是“BaseClass”。这与我认为的 c# 不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-17
  • 2013-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多