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

SL & STL C++ Discussion :

Probleme de virtualisation


Sujet :

SL & STL C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2006
    Messages
    27
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2006
    Messages : 27
    Par défaut Probleme de virtualisation
    Bonjour alors je vous expose mon probleme. Je suis entrain de tenter de creer un petit jeu. Dans celui-ci j'ai implementé trois classes :
    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
     
    class Thread
    {
    private:
        Glib::Thread* _thread;
        bool _is_joignable;
        bool _is_running;
     
    public:
        static void init();
        Thread(bool joignable=FALSE);
        virtual ~Thread();
        void start();
        virtual void run();
        virtual void stop();
        bool isJoignable()const;
        bool isRunning()const;
        static void sleep(unsigned long delay);
    };
    voici le code du run de la classe thread juste pour exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    void Thread::run(){
        while(true)cout << "Thread.run" << endl;
    }
    Puis j'ai concu la cette classe qui herite de thread

    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
     
    template <class T> class Agent : public Thread 
    { 
    private: 
        queue<T>_messages; 
        string _name;
        Glib::Mutex _mutex;
        //Semaphore *_sem; 
     
    public: 
        Agent(void); 
        Agent(string name); 
        virtual ~Agent(void); 
        virtual void initialize();                     
        virtual void finalize();                 
        bool haveMessages()const;             
        T readMessage();         
        void sendMessage(T message); 
        string getName()const;
        virtual void run();                     
    };
    Voici le corps de la méthode run ke j'ai cree juste pour voir le deroulement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    template <class T> void Agent<T>::run(){
        while(true)cout << "Agent.run" << endl;
    }
    Et enfin voila mon probleme j'ai cree cette classe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class GameEngineKeyboardReaderAgent: public Agent<XmlMessage>{
    private:
        GameEngine* _engine;
        unsigned long _delay;
     
    public:
        GameEngineKeyboardReaderAgent(GameEngine* engine,unsigned long delay=250000);
        virtual ~GameEngineKeyboardReaderAgent();
        virtual void run();
    };
    Lors de mon execution pourquoi c'est la méthode run de la classe Agent qui est exécutée et non la méthode run de la classe GameEngineKeyboardReaderAgent que j'ai cree?

    J'espere que quelqu'un trouvera la solution a mon probleme.

  2. #2
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Pendant l'exécution d'un constructeur ou d'un destructeur, le type dynamique est le type construit. Donc les fonctions virtuelles sont celles définies dans le type construit.

    Une des raisons: la fonction virtuelle peut utiliser des membres, et ceux-ci ne seraient pas encore construit ou déjà détruit si la fonction appelée était celle de la classe la plus dérivée.

  3. #3
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2006
    Messages
    27
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2006
    Messages : 27
    Par défaut
    Je ne comprend pas vraiment ce que tu me dis. Pourtant j'ai beau relire, lol.
    j'ai une variable GameEngineKeyboardReaderAgent, ce n'est pas un pointeur.
    Quand j'apelle la méthode run de celle-ci pourquoi ce n'est pas celle de cette classe qui est executée.
    Le probleme n'est pas du au fait que la classe Agent soit faite a l'aide de templates?

  4. #4
    Membre Expert
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Par défaut
    Ton problème doit venir d'autre part.
    Exemple:

    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
    #include <iostream>
     
    using namespace std;
     
    class A
    {
        public:
            virtual void run() { cout << "A!! " << endl; }
    };
     
    template <class T>
    class B :public A
    {
        public:
            virtual void run() { cout << "B!! " << endl; }
    };
     
    class C : public B<int>
    {
        public:
            virtual void run() { cout << "C!! " << endl; }
    };
     
    int main()
    {
        C obj;
        obj.run();
        return 0;
    }
    Ce code marche parfaitement.

    Où fais-tu l'appel à run()? Tu peux montrer comment tu le fais?

  5. #5
    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 : 50
    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
    Par défaut
    Citation Envoyé par ultimate_manx Voir le message
    Je ne comprend pas vraiment ce que tu me dis. Pourtant j'ai beau relire, lol.
    Je vais tenter de reformuler l'explication de Jean-Marc, en détaillant plus. Une variable possède deux type, l'un statique, l'autre dynamique. Posons C qui dérive de B qui dérive de A. Par exemple, dans :

    La variable a possède comme type statique (son type déclaré dans le programme) A*. Par contre, son type dynamique est B*. Une fonction virtuelle est simplement une fonction dont on va chercher le code en utilisant le type dynamique de la variable, au lieu de son type statique, comme une fonction classique.

    Maintenant, quand on fait new C(), la création se passe ainsi :
    - On alloue assez de mémoire pour un objet de taille C.
    - On initialise la sous partie correspondant à A de l'objet
    - On appelle le corps du constructeur de A. Pendant cet appel, l'objet crée a pour type dynamique A.
    - On initialise la sous partie correspondant à B de l'objet
    - On appelle le corps du constructeur de B. Pendant cet appel, l'objet crée a pour type dynamique B.
    - On initialise la sous partie correspondant à C de l'objet
    - On appelle le corps du constructeur de C. Pendant cet appel, l'objet crée a pour type dynamique C.

    Donc, dans le corps du constructeur de la classe B, un appel de fonction virtuel appellera la fonction définie dans la classe B, et non pas celle définie dans la classe C. D'ailleurs, si la fonction est virtuelle pure dans B, ça causera quelques problèmes.

    Maintenant, pourquoi cette règle ? Une fonction définie dans C a accès aux données membre de C. Or, on a vu que au moment où on exécute l'appel au corps du constructeur de B, ces dernières ne sont pas encore crées. On a donc préférer jouer la sécurité.
    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.

  6. #6
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2006
    Messages
    27
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2006
    Messages : 27
    Par défaut
    Voici mes constructeurs :

    Celui de la classe Thread:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Thread::Thread(bool joignable){
        Thread::init();
        _is_joignable = joignable;
    }
    Celui de la classe agent :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template <class T>Agent<T>::Agent(void){
        _num_agent++;
        ostringstream oss;
        oss << _num_agent;
        new (this) Agent(oss.str());
    }
    Celui de la classe GameEngineKeyboardReaderAgent:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    GameEngineKeyboardReaderAgent::GameEngineKeyboardReaderAgent(GameEngine* engine,unsigned long delay):Agent<XmlMessage>(){
        _engine = engine;
        _delay = delay;
    }

    Maintenant l'appel a la méthode run se fait a partir de la classe start du thread, voici son code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    static void _start(Thread* t){
        t->run();
    }
     
    void Thread::start(){
        _is_running = true;
        _thread = Glib::Thread::create(sigc::bind<Thread*>(&_start,(Thread*)this),false);
    }

    voila j'espere que cela vous permettra de mieux comprendre mon probleme.

  7. #7
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2006
    Messages
    27
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2006
    Messages : 27
    Par défaut
    Désolé je m'étais trompé de thread.
    La solution que j'ai présenté fonctionne tres bien. Par contre si vous voyez des améliorations ou de possibles erreures de code je suis preneur.

    Merci de votre aide.

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    410
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 410
    Par défaut
    question, dans le constructeur de Agent, à quoi sert ta ligne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    new (this) Agent(oss.str());
    ?

  9. #9
    Invité
    Invité(e)
    Par défaut
    Oups!!!!

    Si je comprends bien, tu utilises un "placement new" pour appeler le constructeur avec un paramètre depuis celui par défaut.

    C'est mal!

    Très mal!

    C'est "ne-fais-jamais-ça" mal!

    Règle d'or: la mécanique de construction et de destruction, c'est le boulot du compilateur. Corrige déjà cela (pourquoi ne pas simplement affecter le string directement?) et je jetterai un coup d'oeil au reste du code.

    new (ailleurs) Carl

  10. #10
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2006
    Messages
    27
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2006
    Messages : 27
    Par défaut
    Je suis désolé j'avais un problème de connection.
    le code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    new (this) Agent(oss.str());
    permet de faire appel a un autre constructeur de la classe. En recherchant sur le net j'ai trouvé ceci. Tu peux m'expliquer pourquoi cela est il mal? J'ai cherché comment le faire car je programme en Java et il est possible d'appeler un constructeur dans un autre a l'aide this(<parametres>).

    Pourquoi l'equivalent en C++ est il deconseillé?

  11. #11
    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 : 50
    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
    Par défaut
    En C++, l'appel au placement new n'est pas un appel à une fonction "constructeur". Il va, dans l'ordre :
    - Construire la sous partie de l'objet correspondant aux classes de base éventuelles.
    - Construire les données membre de l'objet, avec éventuellement les infos de la liste d'initialisation
    - Appeler le code du constructeur.

    Et donc, en faisant ça, les données membre et sous-parties correspondant aux classes de base seront construites deux fois, et détruites une seule...

    Des gens ont évoqué la possibilité d'appeler un constructeur depuis un autre en C++, mais ça en fait pas (encore ?) partie du langage. En tout cas, la syntaxe n'aura rien à voir avec celle d'un placement new.

    Aujourd'hui, la solution classique est du dupliquer le code, quand il est très petit, ou bien d'écrire une fonction qui sera appelée dans les deux constructeurs.
    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.

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

Discussions similaires

  1. Probleme virtualisation de mon DHCP Linux
    Par sky1989 dans le forum Réseau
    Réponses: 2
    Dernier message: 24/01/2013, 23h30
  2. Probleme sur les chaines de caractere
    Par scorpiwolf dans le forum C
    Réponses: 8
    Dernier message: 06/05/2002, 19h01
  3. [Kylix] Probleme d'execution de programmes...
    Par yopziggy dans le forum EDI
    Réponses: 19
    Dernier message: 03/05/2002, 14h50
  4. [Kylix] Probleme de nombre flottant!!
    Par yopziggy dans le forum EDI
    Réponses: 5
    Dernier message: 02/05/2002, 10h13

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