it-swarm-pt.tech

Como determinar se um objeto é uma instância de certa classe C ++ derivada de um ponteiro para uma classe base no GDB?

Estou depurando um programa C++ com GDB.

Eu tenho um ponteiro para um objeto de determinada classe. O ponteiro é declarado como sendo de alguma superclasse que é estendida por várias subclasses.

Não há campos no objeto para especificar o tipo de classe preciso desse objeto, mas algumas funções virtuais (por exemplo, bool is_xxx ()) são definidas para informar o tipo de classe em tempo de execução.

Existe alguma maneira de dizer o tipo de classe preciso de um objeto no GDB sem chamar essas funções virtuais. Chamar essas funções no GDB pode gerar resultados confusos quando o programa é multiencadeado.

45
user1101096

Use ptype. Se você usá-lo sozinho, obtém o tipo declarado do ponteiro:

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

Para obter o tipo real do objeto apontado, defina a variável "print object":

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

No meu sistema, o ptype ou whatis também mostra apenas o óbvio.

(gdb) whatis pObject
type = QObject *

Mas imprimir a primeira entrada da vtable me ajudou:

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

Aqui, o pObject apontou para um QMessageBox derivado do QObject. Isso funciona apenas se a entrada vtable apontar para um método que é substituído pela classe derivada.

Consulte também: Imprimir tabelas de C++ usando GDB

Editar: imprimir apenas o ponteiro para a vtable funciona mais confiável (embora a saída use o nome desconfigurado e não seja tão legível):

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

GDB 7.11

No GDB 7.11, GCC 5.3.1, Ubuntu 16.04, fazendo apenas:

p *myBase

em algo compilado com:

gcc -O0 -ggdb3

pode ser suficiente, como já mostra:

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

onde MyDerived1 é a classe derivada atual que estamos procurando.

Mas se você fizer além disso:

set print object on

a saída é ainda mais clara e se parece com:

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

Isso também afeta outros comandos como:

ptype myBase

que mostra:

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

ao invés de:

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

Nesse caso, não havia indicação do tipo derivado sem set print object on.

whatis é afetado da mesma forma:

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

Programa de teste:

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

Você não precisa chamar as funções virtuais, você pode apenas ver o endereço da função virtual ou da vtable. Outra maneira é usar o RTTI

2
user685684