Partage
  • Partager sur Facebook
  • Partager sur Twitter

"undefined reference to `vtable for ...' "

Mon débuggeur me dit "undefined reference to `vtable for Ennemi' "

    4 novembre 2021 à 15:29:31

    Je m'entraine à Qt et à la POO en créant un petit jeu (un combat tour par tour contre un ennemi (l'ennemi et le joueur ont les mêmes capacités mais j'ai fait hériter la classe Ennemi à la classe Joueur pour pouvoir programmer l'IA de l'adversaire grâce à un algorithme (je sais pas si c'est la bonne solution car je n'ai pas encore appris à faire une IA))mais mon débuggeur me dit "undefined reference to `vtable for Ennemi' " dans "Ennemi.cpp". Je ne suis pas très doué et je n'ai pas encore fini la partie sur Qt mais je pense que je ne m'en sors pas si mal à part ça (dites moi si j'ai fait une erreur grave). Voici mon code :

    Joueur.h:

    #ifndef JOUEUR_H
    #define JOUEUR_H
    
    #include "Arme.h"
    #include <QObject>
    
    class Joueur : public QObject
    {
        Q_OBJECT
    
    public:
    
        Joueur(QString nom);
        void recevoirDegat(int degat);
    
    
    signals:
        int vieChangee(int vieActuelle);
    
    public slots:
    
        void attaquer(Joueur *cible);
        void seSoigner();
    
    protected:
    
        QString m_nom;
        int m_vie;
        int m_potions;
        Arme *m_arme;
    
    };
    
    #endif // JOUEUR_H

    Joueur.cpp:

    #include "Joueur.h"
    
    Joueur::Joueur(QString nom) : m_nom(nom), m_vie(100), m_potions(3)
    {
        m_arme = new Arme("Épée", 15);
    
        emit vieChangee(m_vie);
    }
    
    void Joueur::recevoirDegat(int degat)
    {
        m_vie -= degat;
    
        if(m_vie>0)
            m_vie=0;
    
        emit vieChangee(m_vie);
    }
    
    void Joueur::attaquer(Joueur *cible)
    {
        cible->recevoirDegat(m_arme->getDegats());
    }
    
    void Joueur::seSoigner()
    {
        if(m_potions>0)
        {
            m_vie+=20;
    
            if(m_vie>100)
            {
                m_vie = 100;
            }
    
            --m_potions;
    
            emit vieChangee(m_vie);
        }
    }
    Arme.h:
    #ifndef ARME_H
    #define ARME_H
    
    #include <QString>
    
    class Arme
    {
    public:
    
        Arme(QString nom, int degats);
        void changer(QString nom, int degats);
        int getDegats() const;
    
    private:
        QString m_nom;
        int m_degats;
    };
    
    #endif // ARME_H

    Arme.cpp:
    #include "Arme.h"
    
    Arme::Arme(QString nom, int degats) : m_nom(nom), m_degats(degats)
    {
    
    }
    
    void Arme::changer(QString nom, int degats)
    {
        m_nom=nom;
        m_degats=degats;
    }
    
    int Arme::getDegats() const
    {
        return m_degats;
    }
    

    Ennemi.h:
    #ifndef ENNEMI_H
    #define ENNEMI_H
    
    #include "Arme.h"
    #include "Joueur.h"
    #include <QString>
    #include <QObject>
    
    class Ennemi : public Joueur
    {
    Q_OBJECT
    
    public:
        Ennemi(QString nom);
    
    public slots:
        void agir(Joueur *cible);
    };
    
    #endif // ENNEMI_H
    

    Ennemi.cpp:
    #include "Ennemi.h"
    
    Ennemi::Ennemi(QString nom) : Joueur(nom)
    {
    
    }
    
    void Ennemi::agir(Joueur *cible)
    {
        if(m_vie <= 20 && m_potions != 0)
        {
            seSoigner();
        }
        else
            attaquer(cible);
    
    }
    Je rajoute un screenshot de Ennemi.cpp pour que vous voyez les messages du débuggeur:
    Je mets aussi le reste de mon code si vous voulez me donner des conseils:
    Fenetre.h:
    #ifndef FENETRE_H
    #define FENETRE_H
    
    #include <QWidget>
    #include <QPushButton>
    #include <QProgressBar>
    
    class Fenetre : public QWidget
    {
    public:
        Fenetre();
    
    private:
        QPushButton *m_boutonAttaque;
        QPushButton *m_boutonSoin;
        QPushButton *m_boutonChangerArme;
        QProgressBar *m_barreVie;
    
    };
    
    #endif // FENETRE_HLayout;
    Fenetre.cpp:
    #include "Fenetre.h"
    #include "Joueur.h"
    #include "Ennemi.h"
    #include <QGridLayout>
    #include <QVBoxLayout>
    
    
    Fenetre::Fenetre()
    {
        QGridLayout *layout = new QGridLayout;
    
        Joueur joueur("John Doe");
        Ennemi ennemi("Lee Smith");
    
        QPushButton *m_boutonAttaque = new QPushButton("Attaquer");
        QPushButton *m_boutonSoin = new QPushButton("Se soigner");
        QPushButton *m_boutonInfo = new QPushButton();
        QProgressBar *m_barreVie = new QProgressBar();
    
        QObject::connect(m_boutonAttaque, SIGNAL(clicked()), &joueur, SLOT(attaquer(&ennemi)));
        QObject::connect(&joueur, SIGNAL(vieChangee(int)), m_barreVie, SLOT(setValue(int)));
        m_barreVie->setValue(100);
    
        layout->addWidget(m_boutonAttaque, 1, 1);
        layout->addWidget(m_boutonSoin, 1, 2);
    
        QVBoxLayout *layoutPrincipal = new QVBoxLayout;
    
        layoutPrincipal->addWidget(m_boutonInfo);
        layoutPrincipal->addLayout(layout);
        layoutPrincipal->addWidget(m_barreVie);
    
        setLayout(layoutPrincipal);
    }
    main.cpp:
    #include <QApplication>
    #include "Fenetre.h"
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc,argv);
    
        Fenetre fenetre;
        fenetre.show();
    
        return app.exec();
    }
    
    Voilà, merci pour votre aide!
    Edit: J'utilise un bouton qui ne fera rien d'autre qu'afficher du texte pour les infos parce que je ne sais pas comment faire autrement, même en regardant un peu dans la documentation.

    -
    Edité par Koda_be 4 novembre 2021 à 16:27:22

    • Partager sur Facebook
    • Partager sur Twitter
      8 novembre 2021 à 11:52:52

      J'y connais rien en Qt, mais :

      http://gcc.gnu.org/faq.html#vtables

      Je pense que vous avez oublié un des pré-requis pour dériver "correctement" de QObject.

      -
      Edité par bacelar 8 novembre 2021 à 11:53:05

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        9 novembre 2021 à 1:50:07

        Salut,
        Essaye la commande qmake avant de recompiler.
        Et sinon pour :
        QObject::connect(m_boutonAttaque, SIGNAL(clicked()), &joueur, SLOT(attaquer(&ennemi)));
        QObject::connect(&joueur, SIGNAL(vieChangee(int)), m_barreVie, SLOT(setValue(int)));
            
        La première n'est pas bonne, les arguments ne sont pas les mêmes entre signal/slot
        Et comme tu peut le voir ici : https://doc.qt.io/qt-6/signalsandslots.html
        Ont utilise connect comme ça maintenant :
        QObject::connect(&joueur, &Joueur::vieChangee, m_barreVie, &QProgressBar::setValue);
        • Partager sur Facebook
        • Partager sur Twitter
          9 novembre 2021 à 8:51:08

          Avant de répondre à la question :

          • Pas de pointeurs nu, pourquoi tu fait un pointeur alors que Arme n'est visiblement pas polymorphique ?
          • Tu as l'air d'avoir suivi le cours de C++ du site, tu peux recommencer un cours plus à jour couvrant les dernières normes (C++11, C++14, C++17, C++20, C++23).
          • Le polymorphisme et l'orienté objet se présente assez mal dans la conception d'un jeu vidéo.
          • S'il te plait ne code pas en français.

          Pour ton problème, il semblerait qu'il manque des définitions. Probablement l'appel à moc manquant. Montre nous ton fichier .pro

          -
          Edité par markand 9 novembre 2021 à 8:51:47

          • Partager sur Facebook
          • Partager sur Twitter

          git is great because Linus did it, mercurial is better because he didn't.

            10 novembre 2021 à 18:26:47

            9kny4 a écrit:

            Salut,
            Essaye la commande qmake avant de recompiler.
            Et sinon pour :
            QObject::connect(m_boutonAttaque, SIGNAL(clicked()), &joueur, SLOT(attaquer(&ennemi)));
            QObject::connect(&joueur, SIGNAL(vieChangee(int)), m_barreVie, SLOT(setValue(int)));
                
            La première n'est pas bonne, les arguments ne sont pas les mêmes entre signal/slot
            Et comme tu peut le voir ici : https://doc.qt.io/qt-6/signalsandslots.html
            Ont utilise connect comme ça maintenant :
            QObject::connect(&joueur, &Joueur::vieChangee, m_barreVie, &QProgressBar::setValue);

            Que me conseillez-vous de faire pour arranger pouvoir me servir du slot "attaquer(&ennemi)"? J'ai pensé à peut-être créer un autre slot qui émet un signal spécial utilisable par le slot, mais je me suis demandé de un, si cela ne surchargerait pas un peu trop le programme; et de deux, comment je pourrais le faire parce que la, aucune idée.

            markand a écrit:

            Avant de répondre à la question :

            • Pas de pointeurs nu, pourquoi tu fait un pointeur alors que Arme n'est visiblement pas polymorphique ?
            • Tu as l'air d'avoir suivi le cours de C++ du site, tu peux recommencer un cours plus à jour couvrant les dernières normes (C++11, C++14, C++17, C++20, C++23).
            • Le polymorphisme et l'orienté objet se présente assez mal dans la conception d'un jeu vidéo.
            • S'il te plait ne code pas en français.

            Pour ton problème, il semblerait qu'il manque des définitions. Probablement l'appel à moc manquant. Montre nous ton fichier .pro

            -
            Edité par markand hier à 8:51

            J'ai écrit en français que parce j'étais la seule personne à coder, sinon je l'aurais mis en anglais.

            J'ai remarqué qu'il était inutile d'avoir un pointeur vers un objet Arme, je l'ai donc supprimé.

            Voici mon fichier .pro:

            QT+=widgets
            SOURCES+=\
            Arme.cpp\
            Ennemi.cpp\
            Fenetre.cpp\
            Joueur.cpp\
            main.cpp
            HEADERS+=\
            Arme.h\
            Ennemi.h\
            Fenetre.h\
            Joueur.h\


            Merci beaucoup pour votre aide.

            -
            Edité par Koda_be 10 novembre 2021 à 18:38:43

            • Partager sur Facebook
            • Partager sur Twitter

            "undefined reference to `vtable for ...' "

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown