我正在使用GDB调试C ++程序。
我有一个指向某个类的对象的指针。该指针被声明为一些超类,它由几个子类扩展。
对象中没有字段指定此对象的精确类类型,但是定义了一些虚函数(例如bool is_xxx())以在运行时告诉类类型。
有没有办法在不调用这些虚函数的情况下告诉GDB中对象的精确类类型。当程序是多线程的时,在GDB中调用这些函数可能会产生令人困惑的结果。
答案 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