Comment déterminer si un objet est une instance d'une certaine classe C++ dérivée d'un pointeur vers une classe de base dans GDB?

je débogue un programme C++ avec GDB.

j'ai un pointeur vers un objet d'une certaine classe. Le pointeur est déclaré être d'une certaine classe super qui est étendue par plusieurs sous-classes.

il n'y a pas de champs dans l'objet pour spécifier le type de classe précis de cet objet, mais certaines fonctions virtuelles (par exemple bool is_xxx()) sont définies pour indiquer le type de classe à l'exécution.

est-il un moyen de dire la classe précise tapez un objet dans GDB sans appeler ces fonctions virtuelles. Appeler de telles fonctions dans GDB peut générer des résultats confus lorsque le programme est multi-threadé.

41

4 réponses

utiliser ptype . Si vous l'utilisez seul, vous obtenez le type déclaré du pointeur:

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

pour obtenir le type réel de l'objet pointé, définissez la variable "print object":

(gdb) set print object on
(gdb) ptype ptr
type = /* real type = DerivedClass * */
class SuperClass {
  // various members
} *
46
répondu Beta 2011-12-16 02:28:29

sur mon ptype système ou qui montre aussi seulement l'évident.

(gdb) whatis pObject
type = QObject *

mais l'impression de la première entrée du vtable m'a aidé:

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

ici le pObject pointait vers une QMessageBox qui est dérivé de QObject. Cela fonctionne seulement si vtable-points d'entrée à une méthode qui est dépassée par la classe dérivée.

voir aussi: Imprimer C++ vtables l'utilisation de GDB

Modifier: imprimer seulement le pointeur vers les travaux vtable plus fiable (bien que la sortie utilise le nom mutilé et n'est pas si lisible):

(gdb) p /a (*(void ***)pObject)
 = 0xb4af33a0 <_ZTV11QMessageBox+8>
13
répondu Joachim 2017-05-23 11:54:50

GDB 7.11

de GDB 7.11, GCC 5.3.1, Ubuntu 16.04, en faisant simplement:

p *myBase

sur quelque chose compilé avec:

gcc -O0 -ggdb3

peut être suffisant comme il le montre déjà:

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

MyDerived1 est la classe dérivée courante que nous recherchons.

mais si vous le faites en plus:

set print object on

la sortie est encore plus claire et ressemble à:

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

Cela affecte aussi d'autres commandes comme:

ptype myBase

qui montre:

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

au lieu de:

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

dans ce cas, il n'y avait pas d'indication du type dérivé sans set print object on .

whatis est également affecté:

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

programme d'essai:

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

Vous n'avez pas besoin d'appeler les fonctions virtuelles, vous pouvez voir l'adresse de la fonction virtuelle ou vtable. Une autre façon est D'utiliser RTTI

2
répondu user685684 2011-12-16 02:08:47