如何确定一个对象是否是从GDB的一个指向基类的指针派生的C ++类的实例?
我正在用GDBdebugging一个C ++程序。
我有一个指向某个类的对象的指针。 指针被声明为一些超类,它被几个子类扩展。
在对象中没有字段来指定这个对象的精确类的types,但是一些虚函数(例如bool is_xxx())被定义为在运行时告诉类的types。
有没有一些方法可以在不调用这些虚函数的情况下告诉GDB中对象的精确类的types。 在GDB中调用这样的函数可能会在程序是multithreading时产生混乱的结果。
使用ptype
。 如果你自己使用它,你会得到指针的声明types:
(gdb) ptype ptr type = class SuperClass { // various members } *
要获得指向的对象的实际types,请设置“打印对象”variables:
(gdb) set print object on (gdb) ptype ptr type = /* real type = DerivedClass * */ class SuperClass { // various members } *
在我的系统ptype或什么也只显示明显。
(gdb) whatis pObject type = QObject *
但是打印vtable的第一个入口帮助了我:
(gdb) p /a (*(void ***)pObject)[0] $4 = 0xb4b4cdf4 <QMessageBox::metaObject() const>
这里的pObject指向从QObject派生的QMessageBox。 这只适用于如果vtable-entry指向由派生类覆盖的方法。
另请参阅: 使用GDB打印C ++ vtables
编辑:只打印指向vtable的指针工作更可靠(虽然输出使用了错位的名称,不太可读):
(gdb) p /a (*(void ***)pObject) $5 = 0xb4af33a0 <_ZTV11QMessageBox+8>
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
没有指示派生types。
whatis
也同样受到影响:
(gdb) whatis myBase type = MyBase * (gdb) set print object on (gdb) whatis myBase type = /* real type = MyDerived1 * */ MyBase *
testing程序:
#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; }
你不需要调用虚函数,你可以看到虚函数或虚表的地址。 另一种方法是使用RTTI