如何从GDB中指向基类的指针确定某个对象是否是某个派生C ++类的实例?

时间:2011-12-16 01:59:46

标签: c++ types gdb superclass instanceof

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

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

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

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

4 个答案:

答案 0 :(得分:50)

使用ptype。如果您单独使用它,则获得指针的声明类型:

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

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

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

答案 1 :(得分:16)

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

(gdb) whatis pObject
type = QObject *

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

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

这里pObject指向一个从QObject派生的QMessageBox。 仅当vtable-entry指向由派生类重写的方法时才有效。

另见: Print C++ vtables using GDB

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

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

答案 2 :(得分:7)

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;
}

答案 3 :(得分:2)

您无需调用虚函数,只需查看虚函数或vtable的地址即可。 另一种方法是使用RTTI