【问题标题】:How to determine if an object is an instance of certain derived C++ class from a pointer to a base class in GDB?如何从指向 GDB 中基类的指针确定对象是否是某个派生 C++ 类的实例?
【发布时间】:2012-01-21 16:10:01
【问题描述】:

我正在用 GDB 调试一个 C++ 程序。

我有一个指向某个类的对象的指针。指针被声明为由几个子类扩展的某个超类。

对象中没有字段来指定该对象的精确类类型,但定义了一些虚函数(例如 bool is_xxx())在运行时告诉类类型。

有没有办法在不调用这些虚函数的情况下告诉 GDB 中对象的精确类类型。当程序是多线程时,在 GDB 中调用此类函数可能会产生令人困惑的结果。

【问题讨论】:

  • 我不是 gdb 专家,但您可能能够遍历 v-table 指针(这是您的基类指针字面上指向的内容)并解析函数的名称。跨度>
  • @selbie 咨询 v-table 正是 ptype 在 {set print object on} 处于活动状态时所做的事情,正如 Beta 在他/她的回答中指出的那样

标签: c++ types gdb superclass instanceof


【解决方案1】:

使用ptype。如果你单独使用它,你会得到指针的声明类型:

(gdb) ptype ptr
type = class SuperClass {
  // various members
} *

要获取指向的对象的实际类型,请设置“打印对象”变量:

(gdb) set print object on
(gdb) ptype ptr
type = /* real type = DerivedClass * */
class SuperClass {
  // various members
} *

【讨论】:

  • ptype 对我不起作用(gdb 7.2)。在set print object on 之后,该课程由p *ptr 打印。
  • @PerJohansson 这对我也不起作用。您找到更好的解决方案了吗?
  • @PerJohansson ptype 在 GDB 7.11 上为我工作 完成 set print object on: stackoverflow.com/a/37054214/895245
  • 查看here 了解如何始终拥有set print object on
【解决方案2】:

在我的系统上 ptype 或 whatis 也只显示明显的。

(gdb) whatis pObject
type = QObject *

但是打印 vtable 的第一个条目帮助了我:

(gdb) p /a (*(void ***)pObject)[0]
$4 = 0xb4b4cdf4 <QMessageBox::metaObject() const>

这里的 pObject 指向一个 QMessageBox,它是从 QObject 派生的。 这仅在 vtable-entry 指向被派生类覆盖的方法时才有效。

另请参阅: Print C++ vtables using GDB

编辑:仅打印指向 vtable 的指针更可靠(尽管输出使用了损坏的名称并且不那么可读):

(gdb) p /a (*(void ***)pObject)
$5 = 0xb4af33a0 <_ZTV11QMessageBox+8>

【讨论】:

【解决方案3】:

GDB 7.11

从 GDB 7.11、GCC 5.3.1、Ubuntu 16.04 开始:

p *myBase

关于编译的东西:

gcc -O0 -ggdb3

可能已经足够了:

$1 = {_vptr.MyBase = 0x400c00 <vtable for MyDerived1+16>}

其中MyDerived1 是我们正在寻找的当前派生类。

但如果你还这样做:

set print object on

输出更清晰,看起来像:

$1 = (MyDerived1) {<MyBase> = {_vptr.MyBase = 0x400c00 <vtable for MyDerived1+16>}, <No data fields>}

这也会影响其他命令,例如:

ptype myBase

其中显示:

type = /* real type = MyDerived1 * */
class MyBase {
  public:
    virtual int myMethod(void);
} *

代替:

type = class MyBase {
  public:
    virtual int myMethod(void);
} *

在这种情况下,没有set print object on 就没有派生类型的指示。

whatis 同样受到影响:

(gdb) whatis myBase
type = MyBase *
(gdb) set print object on
(gdb) whatis myBase
type = /* real type = MyDerived1 * */
MyBase *

测试程序:

#include <iostream>

class MyBase {
    public:
        virtual int myMethod() = 0;
};

class MyDerived1 : public MyBase {
    public:
        virtual int myMethod() { return 1; }
};

class MyDerived2 : public MyBase {
    public:
        virtual int myMethod() { return 2; }
};

int main() {
    MyBase *myBase;
    MyDerived1 myDerived1;
    MyDerived2 myDerived2;
    myBase = &myDerived1;
    std::cout << myBase->myMethod() << std::endl;
    myBase = &myDerived2;
    std::cout << myBase->myMethod() << std::endl;
}

【讨论】:

    【解决方案4】:

    你不需要调用虚函数,你可以看到虚函数或vtable的地址。 另一种方法是使用RTTI

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-16
      • 2015-08-26
      • 2014-08-11
      • 1970-01-01
      • 2011-07-20
      • 2017-07-18
      • 2021-05-20
      • 2011-08-09
      相关资源
      最近更新 更多