How to determine if an object is an instance of certain derived C++ class from a pointer to a base class in GDB?

风流意气都作罢 提交于 2019-11-28 16:49:52

Use ptype. If you use it by itself, you get the declared type of the pointer:

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

To get the actual type of the object pointed to, set the "print object" variable:

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

On my system ptype or whatis also only show the obvious.

(gdb) whatis pObject
type = QObject *

But printing the first entry of the vtable helped me:

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

Here the pObject pointed to a QMessageBox which is derived from QObject. This only works if vtable-entry points to a method that is overridden by the derived class.

See also: Print C++ vtables using GDB

Edit: Printing only the pointer to the vtable works more reliable (though the output uses the mangled name and is not so readable):

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

GDB 7.11

As of GDB 7.11, GCC 5.3.1, Ubuntu 16.04, doing just:

p *myBase

on something compiled with:

gcc -O0 -ggdb3

may be enough as it already shows:

$1 = {_vptr.MyBase = 0x400c00 <vtable for MyDerived1+16>}

where MyDerived1 is the current derived class we are looking for.

But if you do in addition:

set print object on

the output is even clearer and looks like:

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

This also affects other commands like:

ptype myBase

which shows:

type = /* real type = MyDerived1 * */
class MyBase {
  public:
    virtual int myMethod(void);
} *

instead of:

type = class MyBase {
  public:
    virtual int myMethod(void);
} *

In this case, there was no indication of the derived type without set print object on.

whatis is similarly affected:

(gdb) whatis myBase
type = MyBase *
(gdb) set print object on
(gdb) whatis myBase
type = /* real type = MyDerived1 * */
MyBase *

Test program:

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

You do not need to call the virtual functions, you can just see the address of the virtual function or vtable. Another way is to use RTTI

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!