How to determine if an object is an instance of ce

2019-01-21 10:47发布

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.

4条回答
一纸荒年 Trace。
2楼-- · 2019-01-21 11:14

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;
}
查看更多
趁早两清
3楼-- · 2019-01-21 11:15

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
} *
查看更多
啃猪蹄的小仙女
4楼-- · 2019-01-21 11:26

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>
查看更多
干净又极端
5楼-- · 2019-01-21 11:27

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

查看更多
登录 后发表回答