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

use*_*096 44 c++ types gdb instanceof superclass

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

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

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

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

Bet*_*eta 52

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

(gdb) ptype ptr
type = class SuperClass {
  // various members
} *
Run Code Online (Sandbox Code Playgroud)

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

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

  • `ptype`对我不起作用(gdb 7.2).在`set print object on`之后,该类由`p*ptr`打印. (12认同)

Joa*_*him 16

在我的系统上,ptype或whatis也只是显示出明显的.

(gdb) whatis pObject
type = QObject *
Run Code Online (Sandbox Code Playgroud)

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

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

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

另请参阅: 使用GDB打印C++ vtable

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

(gdb) p /a (*(void ***)pObject)
$5 = 0xb4af33a0 <_ZTV11QMessageBox+8>
Run Code Online (Sandbox Code Playgroud)


Cir*_*四事件 7

GDB 7.11

从GDB 7.11,GCC 5.3.1,Ubuntu 16.04开始,仅执行以下操作:

p *myBase
Run Code Online (Sandbox Code Playgroud)

关于编译的东西:

gcc -O0 -ggdb3
Run Code Online (Sandbox Code Playgroud)

可能就足够了,因为它已经显示:

$1 = {_vptr.MyBase = 0x400c00 <vtable for MyDerived1+16>}
Run Code Online (Sandbox Code Playgroud)

MyDerived1我们正在寻找的当前派生类在哪里.

但如果你这样做:

set print object on
Run Code Online (Sandbox Code Playgroud)

输出更清晰,看起来像:

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

这也会影响其他命令:

ptype myBase
Run Code Online (Sandbox Code Playgroud)

这表现了:

type = /* real type = MyDerived1 * */
class MyBase {
  public:
    virtual int myMethod(void);
} *
Run Code Online (Sandbox Code Playgroud)

代替:

type = class MyBase {
  public:
    virtual int myMethod(void);
} *
Run Code Online (Sandbox Code Playgroud)

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

whatis 同样受到影响:

(gdb) whatis myBase
type = MyBase *
(gdb) set print object on
(gdb) whatis myBase
type = /* real type = MyDerived1 * */
MyBase *
Run Code Online (Sandbox Code Playgroud)

测试程序:

#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;
}
Run Code Online (Sandbox Code Playgroud)


小智 1

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