2011-12-16 1 views
41

Я отлаживаю программу на C++ с помощью GDB.Как определить, является ли объект экземпляром определенного производного класса C++ из указателя на базовый класс в GDB?

У меня есть указатель на объект определенного класса. Указатель объявлен как некоторый суперкласс, который расширен несколькими подклассами.

В объекте нет полей для указания точного типа этого объекта, но некоторые виртуальные функции (например, bool is_xxx()) определены для указания типа класса во время выполнения.

Есть ли способ рассказать точный тип класса объекта в GDB без вызова этих виртуальных функций. Вызов таких функций в GDB может привести к запутанному результату, когда программа многопоточная.

+0

Я не GDB профессионалом, но вы можете быть в состоянии пройти через указатель v-таблицы (который является то, что ваша база указатель класса буквально указывает на) и разрешает имя функций. – selbie

+0

@selbie, консультирующийся с v-столом, именно то, что ptype делает под капотом, если объект {set print object on} активен, как указывал Бета в своем ответе –

ответ

2

Вам не нужно вызывать виртуальные функции, вы можете просто увидеть адрес виртуальной функции или vtable. Другим способом является использование RTTI

45

Использование ptype. Если вы используете его самостоятельно, вы получите объявленный тип указателя:

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

Чтобы получить фактический тип объекта указал, установить «печать объекта» переменная:

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

'ptype' не работал для меня (gdb 7.2). После того, как 'set print object on', класс был напечатан' p * ptr'. –

+1

@PerJohansson Это не сработало для меня. Вы нашли лучшее решение? –

+0

@PerJohansson 'ptype' работает для меня на GDB 7.11 * после * делает' set print object on': http://stackoverflow.com/a/37054214/895245 –

12

О моя система ptype или whatis также показывает только очевидное.

(gdb) whatis pObject 
type = QObject * 

Но печать первой записи в таблице виртуального помогла мне:

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

Здесь pObject указал на QMessageBox, который является производным от QObject. Это работает только в том случае, если vtable-entry указывает на метод, который переопределяется производным классом.

Смотрите также: Print C++ vtables using GDB

Edit: Печать только указатель на таблицу виртуальных работает более надежным (хотя выход использует искаженное имя и не так читаемым):

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

[вторая запись в таблице vtable] (http://stackoverflow.com/questions/5712808/understanding-the-vtable-entries) указывает на 'type_info'. Это всегда переоценивается. – MSalters

6

GDB 7,11

по БГД 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; 
} 
Смежные вопросы