How to determine if an object is an instance of certain derived C++ class from a pointer to a base class in GDB?
I'm debugging a C++ program with GDB.
I have a pointer to an object of certain class. The pointer is declared to be of some super class which is extended by several sub-classes.
There is no fields in the object to specify the precise class type of this object but some virtual functions (e.g. bool is_xxx()) are defined to tell the class type at runtime.
Is there some way to tell the precise class type of an object in GDB without calling these virtual functions. Calling such functions in GDB may generate confusing result when the program is multi-threaded.
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
} *
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;
}