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 ++程序。
我有一个指向某个类的对象的指针。 指针被声明为某些超类,它由几个子类扩展。
对象中没有字段指定此对象的精确类类型,但是定义了一些虚函数(例如bool is_xxx())以在运行时告知类类型。
有没有办法在不调用这些虚函数的情况下告诉GDB中对象的精确类类型。 当程序是多线程的时,在GDB中调用这些函数可能会产生令人困惑的结果。
使用
1 2 3 4 | (gdb) ptype ptr type = class SuperClass { // various members } * |
要获取指向的对象的实际类型,请设置"print object"变量:
1 2 3 4 5 6 | (gdb) set print object on (gdb) ptype ptr type = /* real type = DerivedClass * */ class SuperClass { // various members } * |
在我的系统上,ptype或whatis也只是显示出明显的。
1 2 | (gdb) whatis pObject type = QObject * |
但打印vtable的第一个条目帮助我:
1 2 | (gdb) p /a (*(void ***)pObject)[0] $4 = 0xb4b4cdf4 <QMessageBox::metaObject() const> |
这里pObject指向一个从QObject派生的QMessageBox。
仅当vtable-entry指向由派生类重写的方法时,此方法才有效。
也可以看看:
使用GDB打印C ++ vtable
编辑:仅打印指向vtable的指针更可靠(尽管输出使用了损坏的名称并且不那么可读):
1 2 | (gdb) p /a (*(void ***)pObject) $5 = 0xb4af33a0 <_ZTV11QMessageBox+8> |
GDB 7.11
从GDB 7.11,GCC 5.3.1,Ubuntu 16.04开始,仅执行以下操作:
1 | p *myBase |
关于编译的东西:
1 | gcc -O0 -ggdb3 |
可能就足够了,因为它已经显示:
1 | $1 = {_vptr.MyBase = 0x400c00 <vtable for MyDerived1+16>} |
其中
但如果你这样做:
1 | set print object on |
输出更清晰,看起来像:
1 | $1 = (MyDerived1) {<MyBase> = {_vptr.MyBase = 0x400c00 <vtable for MyDerived1+16>}, <No data fields>} |
这也会影响其他命令:
1 | ptype myBase |
这表现了:
1 2 3 4 5 | type = /* real type = MyDerived1 * */ class MyBase { public: virtual int myMethod(void); } * |
代替:
1 2 3 4 | type = class MyBase { public: virtual int myMethod(void); } * |
在这种情况下,没有
1 2 3 4 5 6 | (gdb) whatis myBase type = MyBase * (gdb) set print object on (gdb) whatis myBase type = /* real type = MyDerived1 * */ MyBase * |
测试程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #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; } |
您无需调用虚函数,只需查看虚函数或vtable的地址即可。
另一种方法是使用RTTI