2011-12-16 10 views
41

Estoy depurando un programa C++ con GDB.¿Cómo determinar si un objeto es una instancia de cierta clase derivada de C++ de un puntero a una clase base en GDB?

Tengo un puntero a un objeto de cierta clase. El puntero se declara como de alguna clase superior que se extiende por varias subclases.

No hay campos en el objeto para especificar el tipo de clase exacto de este objeto, pero algunas funciones virtuales (por ejemplo, bool is_xxx()) se definen para indicar el tipo de clase en tiempo de ejecución.

Hay alguna forma de indicar el tipo de clase preciso de un objeto en GDB sin llamar a estas funciones virtuales. Llamar a tales funciones en GDB puede generar resultados confusos cuando el programa tiene múltiples subprocesos.

+0

No soy un mago de GDB, pero que podría ser capaz de atravesar el puntero de tabla v (que es lo que su base de el puntero de clase está literalmente señalando) y resolver el nombre de las funciones. – selbie

+0

@selbie consultar la tabla v es exactamente lo que hace pype bajo el capó si {set print object on} está activo, como señaló Beta en su respuesta –

Respuesta

2

No necesita llamar a las funciones virtuales, solo puede ver la dirección de la función virtual o vtable. Otra forma es usar RTTI

45

Usar ptype. Si lo usa por sí mismo, se obtiene el tipo declarado del puntero:

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

para obtener el tipo real del objeto apuntado, establecer el "objeto de impresión" variables:

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

'ptype' no funcionó para mí (gdb 7.2). Después de 'set print object on' la clase se imprimió por' p * ptr' sin embargo. –

+1

@PerJohansson Tampoco funcionó para mí. ¿Encontraste una mejor solución? –

+0

@PerJohansson 'ptype' funciona para mí en GDB 7.11 * después de * hacer' set print object on': http://stackoverflow.com/a/37054214/895245 –

12

En mi tipo de sistema o whatis también solo muestran lo obvio.

(gdb) whatis pObject 
type = QObject * 

Pero la impresión de la primera entrada de la viable me ayudó:

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

Aquí el pObject señaló un QMessageBox que se deriva de QObject. Esto solo funciona si vtable-entry apunta a un método que la clase derivada anula.

Consulte también: Print C++ vtables using GDB

Editar: Impresión sólo el puntero a la viable funciona de manera más fiable (aunque la salida utiliza el nombre revuelto y no es tan legible):

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

La [segunda entrada en el vtable] (http://stackoverflow.com/questions/5712808/understanding-the-vtable-entries) apunta a 'type_info'. Esto siempre es anulado. – MSalters

6

BGF 7,11

a partir del BGF 7.11, GCC 5.3.1, Ubuntu 16.04, haciendo precisamente:

p *myBase 

en algo compilado con:

gcc -O0 -ggdb3 

puede ser suficiente, ya que ya muestra:

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

donde MyDerived1 es la clase derivada actual que estamos buscando.

Pero si lo hace, además:

set print object on 

la salida es aún más claro y se parece a:

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

Esto también afecta a otros comandos como:

ptype myBase 

que muestra :

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

en lugar de:

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

En este caso, no había ninguna indicación de tipo derivado sin set print object on.

whatis se ven afectados de manera similar: Programa

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

prueba:

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