IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Undefined reference to une classe qui n'existe pas


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2012
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2012
    Messages : 24
    Points : 22
    Points
    22
    Par défaut Undefined reference to une classe qui n'existe pas
    Bonjour, ou bonsoir

    Voila, je bosse actuellement sur un petit projet de jeux vidéo, et j'ai un soucis :

    J'ai une architecture de classe qui est faite de façon à être le plus modulaire possible :
    J'ai notamment la classe "MessageBox", qui est une classe abstraite qui donne la possibilité aux objets de communiquer entre eux, du genre :

    La classe IObject hérite de MessageBox, mais aussi la classe Listener, qui récupère les entrées utilisateurs

    Donc la classe GraphicsEngine est une classe qui hérite de la classe Engine, qui hérite de IObject.

    Voila le problème : tout compile parfaitement, mais au moment du linkage, il y a une erreur parlant de la classe "MessageBoxA". Or, cette classe n'existe tout simplement pas...

    Les erreurs se situent dans le fichier GraphicsEngine.o, et les voici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    ||=== Build: Debug in JV (compiler: GNU GCC Compiler) ===|
    obj\Debug\Sources\Engine\GraphicsEngine.o:GraphicsEngine.cpp:(.rdata$_ZTV14GraphicsEngine[__ZTV14GraphicsEngine]+0x10)||undefined reference to `MessageBoxA::send_message(MessageBoxA*, Message&)'|
    obj\Debug\Sources\Engine\GraphicsEngine.o:GraphicsEngine.cpp:(.rdata$_ZTV14GraphicsEngine[__ZTV14GraphicsEngine]+0x14)||undefined reference to `MessageBoxA::receive_message(Message&)'|
    obj\Debug\Sources\Engine\GraphicsEngine.o:GraphicsEngine.cpp:(.rdata$_ZTV14GraphicsEngine[__ZTV14GraphicsEngine]+0x18)||undefined reference to `MessageBoxA::process_queue()'|
    ||=== Build failed: 3 error(s), 0 warning(s) (0 minute(s), 22 second(s)) ===|
    Voici le code de ma classe MessageBox :
    .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
     
    #ifndef MESSAGEBOX_H
    #define MESSAGEBOX_H
     
    #include <string>
    #include <boost/serialization/serialization.hpp>
    #include <boost/serialization/map.hpp>
    #include <boost/thread.hpp>
    #include <boost/thread/mutex.hpp>
    #include <boost/archive/text_oarchive.hpp>
    #include <OgreVector3.h>
     
    /// \class Message
    /// contiend des structures de données utiles pour les messages inter_objets
     
    struct Message{
        std::string nom;
        std::map<std::string, int> i_values;
        std::map<std::string, bool> b_values;
        std::map<std::string, std::string> s_values;
        std::map<std::string, float> f_values;
    //    std::map<std::string, Ogre::Vector3> v_values;
     
        bool operator==(const Message&);
        template<typename Archive>
        void serialize(Archive& ar, const unsigned int){
            ar & BOOST_SERIALIZATION_NVP(i_values);
            ar & BOOST_SERIALIZATION_NVP(b_values);
            ar & BOOST_SERIALIZATION_NVP(s_values);
            ar & BOOST_SERIALIZATION_NVP(f_values);
    //        ar & BOOST_SERIALIZATION_NVP(v_values);
            ar & BOOST_SERIALIZATION_NVP(nom);
     
        }
    };
     
     
    class MessageBox
    {
        public:
            MessageBox();
            virtual ~MessageBox();
     
            virtual void send_message(MessageBox*, Message&);
            virtual void receive_message(Message&);
            virtual void process_queue();
            virtual void process_message(Message&) = 0;
     
            std::string reportMessage(Message& m);
        protected:
            std::queue<Message> _messages;
            boost::mutex _queue_mutex;
    };
     
    #endif // MESSAGEBOX_H
    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    #include "MessageBox.hpp"
     
    MessageBox::MessageBox()
    {
        //ctor
    }
     
    MessageBox::~MessageBox()
    {
        //dtor
    }
     
    void MessageBox::receive_message(Message& m){
    	_messages.push(m);
    }
     
    void MessageBox::send_message(MessageBox* to, Message& m){
    	to->receive_message(m);
    }
     
    void MessageBox::process_queue(){
    	_queue_mutex.lock();
    	while(!_messages.empty()){
    		Message m;
    		m = _messages.front();
    		_messages.pop();
    		process_message(m);
    	}
    	_queue_mutex.unlock();
    }
     
    std::string MessageBox::reportMessage(Message& m){
        std::ostringstream stream;
        boost::archive::text_oarchive ar(stream);
        ar << m;
        return stream.str();
    }
     
    bool Message::operator==(const Message &m){
        return (nom == m.nom \
                && i_values == m.i_values \
                && b_values == m.b_values \
                && s_values == m.s_values \
                && f_values == m.f_values);
    }
    Et le code de ma classe GraphicsEngine (la classe Engine hérite de IObject, qui hérite de MessageBox)

    .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    #ifndef GRAPHICSENGINE_H
    #define GRAPHICSENGINE_H
     
    #include <iostream>
    #include <Ogre.h>
    #include <CEGUI.h>
    #include <RendererModules\Ogre\CEGUIOgreRenderer.h>
    #include "Engine.hpp"
    #include "../Graphics/WindowListener.hpp"
    #include "../Graphics/GUIListener.hpp"
     
    class GraphicsEngine : public Engine {
        public:
            GraphicsEngine(Game*);
            virtual ~GraphicsEngine();
            void initialise();
            void frame();
            void process_message(Message&);
            void createScene();
            void createViewport();
            void createFrameListener();
        private:
            std::map<std::string, Listener*> _listeners;
     
            CEGUI::OgreRenderer* _renderer;
     
            Ogre::Root* _root;
            Ogre::RenderWindow *_window;
            Ogre::SceneManager *_sceneMgr;
            Ogre::Viewport *_viewport;
     
            Ogre::Camera *_camera;
     
    };
     
    #endif // GRAPHICSENGINE_H
    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
     
    #include "GraphicsEngine.hpp"
    #include "../Game.hpp"
     
    GraphicsEngine::GraphicsEngine(Game* g) : Engine(g), _root(nullptr), _window(nullptr), _sceneMgr(nullptr),
        _viewport(nullptr), _camera(nullptr){
        initialise();
    }
     
    GraphicsEngine::~GraphicsEngine(){
        JLog << std::string("Debut destuction GraphicsEngine");
        delete _root;
        JLog << std::string("Fin destuction GraphicsEngine");
    }
     
    void GraphicsEngine::initialise(){
        _root = new Ogre::Root("plugins.cfg", "ogre.cfg", "Ogre.log");
     
        Ogre::ConfigFile configFile;
        configFile.load("resources.cfg");
     
        Ogre::ConfigFile::SectionIterator seci = configFile.getSectionIterator();
        Ogre::String secName, typeName, archName;
     
        while(seci.hasMoreElements()){
            secName = seci.peekNextKey();
            Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
            Ogre::ConfigFile::SettingsMultiMap::iterator i;
            for(i = settings->begin(); i != settings->end(); ++i){
                typeName = i->first;
                archName = i->second;
                Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
            }
        }
        if(!(_root->restoreConfig() || _root->showConfigDialog())){
            throw Erreur("Chargement de la config", "Erreur lors du chargement de la configuration du moteur graphique", Tools::CRITICAL);
        }
        _window = _root->initialise(true, "Hello World");
     
        Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
        Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
     
        _sceneMgr = _root->createSceneManager("DefaultSceneManager", "Mon ScnMgr");
        _sceneMgr->setAmbientLight(Ogre::ColourValue(1.0f, 1.0f, 1.0f));
     
        createScene();
        createViewport();
        createFrameListener();
    }
     
    void GraphicsEngine::createFrameListener(){
        _listeners["Window"] = new WindowListener(_window);
        _listeners["GUI"] = new GUIListener(_window);
     
        for(auto p : _listeners){
            _root->addFrameListener(p.second);
        }
    }
     
    void GraphicsEngine::createScene(){
        _camera = _sceneMgr->createCamera("PlayerCam");
        _camera->setPosition(Ogre::Vector3(0,0,100));
        _camera->lookAt(Ogre::Vector3(0,0,0));
        _camera->setNearClipDistance(5);
     
    //    Ogre::Light *light = _sceneMgr->createLight("Lum");
    //    light->setType(Ogre::Light::LT_POINT);
    //    light->setPosition(0, 0, 100);
    }
     
    void GraphicsEngine::createViewport(){
        _viewport = _window->addViewport(_camera);
        _viewport->setBackgroundColour(Ogre::ColourValue(0, 0, 1.0f));
        _camera->setAspectRatio(Ogre::Real(_viewport->getActualWidth())/Ogre::Real(_viewport->getActualHeight()));
    }
     
    void GraphicsEngine::process_message(Message& mes){
        if(mes.nom == "afficherModele"){
            std::string nom = mes.s_values["nom"];
            Ogre::SceneNode* node = nullptr;
            if(mes.s_values["parent"] == "root"){
                node = _sceneMgr->getRootSceneNode()->createChildSceneNode((nom+"Node"));
            }else{
                node = _sceneMgr->getSceneNode(mes.s_values["parent"])->createChildSceneNode((nom+"Node"));
            }
            Ogre::Entity *ent = _sceneMgr->createEntity((nom + "Ent"), (nom + ".mesh"));
            node->attachObject(ent);
        }else if(mes.nom == "placerPlan"){
        }else{
        }
    }
     
    void GraphicsEngine::frame(){
        Ogre::WindowEventUtilities::messagePump();
        if(!_root->renderOneFrame() || _window->isClosed()/* || !_root->_updateAllRenderTargets()*/){
            Message m;
            m.nom = "stop";
            send_message(_parent, m);
        }
        process_queue();
    }
    Voila... quelqu'un aurait une solution à mon problème ?

    Merci d'avance !

  2. #2
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2012
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2012
    Messages : 24
    Points : 22
    Points
    22
    Par défaut
    Bon ben problème résolu (je suis une buse)

    En fait, j'avais sans doute un conflit avec une quelconque API (sans doute l'API windows)

    J'ai renommé ma classe, et ça compile et linke parfaitement

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    MessageBox est une fonction windows, et comme toutes celles-ci, il s'agit d'un ignoble #define pointant selon les options de compilation vers MessageBoxA ou MessageBoxW. Tant que tout ton code a les mêmes options de compilation (c'est dans l'onglet général, sur les caractères Unicode, MBCS ou aucun), ce #define ne sera pas trop perturbant. Mais si les options diffèrent, le remplacement ne sera que partiel, et tu auras ce genre de soucis.

    Effectivement, renommer la classe peut résoudre le problème, mais peut rendre le code moins clair. Une autre solution est d'harmoniser tes options de compilation (ce qui est souhaitable de toute manière).
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Sinon, ne serais-ce pas une excellente illustration de l'utilité des namespaces?

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Il n'y a pas seulement les options de compilation, mais aussi le fait d'inclure ou non <windows.h> avant les headers qui définissent la classe.

    Une autre option serait de les #undef dans le header de la classe, puis les re-#define à la fin de ce header (plus un #undef dans le .cpp qui implémenta la classe).

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    //Garde d'inclusion
    //(remplacer par #pragma once si tous les environnements cibles le supportent)
    #ifndef H_MESSAGEBOX_20130705
    #define H_MESSAGEBOX_20130705
     
    #ifdef MessageBox
    #define NEED_REDEF_MessageBox_20130705
    #undef MessageBox
    #endif
     
    class MessageBox
    {
    ...
    };
     
    #ifdef NEED_REDEF_MessageBox_20130705
    #ifdef UNICODE
    #define MessageBox MessageBoxW
    #else
    #define MessageBox MessageBoxA
    #endif
    #undef NEED_REDEF_MessageBox_20130705
    #endif
     
    #endif // ! H_MESSAGEBOX_20130705
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Runtime class loading] Appeler une méthode qui n'existe pas
    Par Invité dans le forum Général Java
    Réponses: 14
    Dernier message: 27/06/2008, 08h48
  2. Charger dynamiquement une classe qui n'est pas dans un jar
    Par rastakouair dans le forum Langage
    Réponses: 12
    Dernier message: 17/12/2007, 19h22
  3. Afficher une liste qui n'existe pas dans la base de données.
    Par Zvetch dans le forum SAP Crystal Reports
    Réponses: 1
    Dernier message: 25/09/2007, 13h23
  4. Pb avec hibernate3, il cherche une table qui n'existe pas
    Par yeddoughmi dans le forum Hibernate
    Réponses: 2
    Dernier message: 22/08/2007, 12h08
  5. Réponses: 8
    Dernier message: 26/01/2006, 14h47

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo