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 :

Appel d'une fonction virtuelle pure dans une méthode membre


Sujet :

Langage C++

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 5
    Points : 4
    Points
    4
    Par défaut Appel d'une fonction virtuelle pure dans une méthode membre
    Bonjour,
    Je possède une classe abstraite de la forme suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    class A{
         protected:
             int foo() = 0;
         public:
             int bar();
    };
    avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    int A::bar(){
        int i = foo();
        // Do some stuff with i
        return i;
    }
    Mon but étant de n'avoir a redéfinir que la fonction foo dans les classe dérivées et éviter la recopie du travail a faire au sein de la fonction bar, qui sera le même dans toutes les classes dérivées.

    Seulement, a la compilation j'obtiens l'erreur suivante:

    error LNK2019: symbole externe non résolu "protected: virtual class A __thiscall A::foo()"

    Quelle est la manière la plus propre de réaliser ce travail pour éviter la recopie du code au sein de toutes les classes filles ?

    Merci pour votre réponse.

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Attention, en C++ (contrairement à C# et à java), les fonctions ne sont pas virtuelles par défaut, car on ne paye que pour ce qu'on utilise.

    Tu dois donc explicitement indiquer que ta fonction est virtuelle si tu veux la déclarer virtuelle pure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class A{
         /* autant la déclarer dans l'accessibilité privée, ca marche aussi */
         private:
             virtual int foo() = 0;
         public:
             int bar(){
                 int i = foo();
                 /* ... */
             }
    };
    (je suis d'ailleurs surpis que le compilateur ne t'aie pas dit que foo devait être virtuelle )

    Ensuite, il faut savoir que le =0 indique que tu ne disposes pas des informations nécessaires pour fournir l'implémentation de la fonction foo, mais que ton compilateur a horreur du vide.

    Du coup la classe A n'est pas instanciable (on parle de "classe abstraite"), et seules les classes dérivées de A pour lesquelles tu auras fourni une implémentation pour foo pourrons être instanciées :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class B : public A{
    /* je ne déclares pas foo et je ne la défini pas pour B */
    };
    class C : public A{
     
        private:
            virtual int foo();
    };
    // dans le fichier d'implémentation
    int C::foo(){
        std::cout<<"C::foo() called "<<std::endl;
        /*...*/
        return 10;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main(){
       A * a = new A; // refusé : A est une classe abstraite à cause de foo
       A * b = new B; // refusé : B est aussi une classe abstraite parce que
                      // foo n'est toujours pas définie
       A * c = new C; // Accepté : C est une classe concrète parce que toutes
                      // les fonctions sont définies
       c->bar(); // affiche bien "C::foo() called"
       /* ... */
    }
    Conclusion : foo doit être explicitement déclarée comme virtual dans A

    Tu peux ommettre le virtual pour la déclaration de foo uniquement dans les classes dérivées de A, mais il reste malgré tout conseillé de le mettre, essentiellement pour "rappeler" au lecteur du code de C que c'est une fonction virutelle (ca permet au lecteur de le savoir sans devoir aller voir du coté du code de A )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 5
    Points : 4
    Points
    4
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,

    Attention, en C++ (contrairement à C# et à java), les fonctions ne sont pas virtuelles par défaut, car on ne paye que pour ce qu'on utilise.

    Tu dois donc explicitement indiquer que ta fonction est virtuelle si tu veux la déclarer virtuelle pure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class A{
         /* autant la déclarer dans l'accessibilité privée, ca marche aussi */
         private:
             virtual int foo() = 0;
         public:
             int bar(){
                 int i = foo();
                 /* ... */
             }
    };
    (je suis d'ailleurs surpis que le compilateur ne t'aie pas dit que foo devait être virtuelle )
    Oui pardon j'ai écris le message (trop) tard. Evidemment foo est déclarée virtuelle.

    Citation Envoyé par koala01 Voir le message
    Ensuite, il faut savoir que le =0 indique que tu ne disposes pas des informations nécessaires pour fournir l'implémentation de la fonction foo, mais que ton compilateur a horreur du vide.
    Une sorte de pointeur de fonction NULL si j'ai bien compris ?

    En fait, je viens de trouver mon erreur. J'appelais ma fonction foo de la meme manière qu'une méthode statique, à savoir:

    int A::bar(){
    int i = A::foo();
    /* ... */
    }
    au lieu de

    int A::bar(){
    int i = foo();
    /* ... */
    }
    D'ailleurs peut t'on m'expliquer comment cette écriture est interprétée ?

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par geekmoule Voir le message
    Oui pardon j'ai écris le message (trop) tard. Evidemment foo est déclarée virtuelle.
    Tu es tout pardonné
    Une sorte de pointeur de fonction NULL si j'ai bien compris ?
    On pourrait dire cela comme ça, oui

    (d'ailleurs, je soupçonnes que c'est effectivement comme cela que le compilateur le considère en interne )
    En fait, je viens de trouver mon erreur. J'appelais ma fonction foo de la meme manière qu'une méthode statique
    Ah, oui, évidemment, dans ce cas là, tu spécifies explicitement que tu veux faire appel à la fonction membre de A.

    Comme le compilateur n'a qu'une intelligence limitée, qu'il sait qu'il dispose d'une fonction nommée foo pour A, il semble "zapper" le fait qu'elle est virtuelle pure, d'où le fait que lui ne se rend pas compte qu'elle n'est pas implémentée.

    Une chance que l'éditeur de liens passe par là après
    D'ailleurs peut t'on m'expliquer comment cette écriture est interprétée ?
    Simplement sous la forme de int i = this->foo();(le pointeur this est implicite pour tout ce qui fait partie des membres de la classes, y compris pour l'appel des fonction, dans le corps des fonctions membres non statiques)

    Comme this est un pointeur, on peut profiter du polymorphisme, et c'est grâce au passage par la table de fonctions virtuelles que la fonction appelée correspond à la "version" de la fonction qui est propre au type réel au départ duquel la fonction est appelée.

    Sois néanmoins attentif au fait que cela ne peut fonctionner que lorsque le type dérivé est entièrement construit.

    Tu ne pourrais donc pas faire appel à bar dans le constructeur de la classe de base (A, selon les exemples), car les parties spécifiques aux types dérivés ne sont pas encore construits, ni dans le destructeur de la classe de base, parce que les parties spécifiques au type dérivé ont déjà été détruites (cf : l'ordre dans lequel les différents éléments sont construits et détruits lors d'un héritage)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 5
    Points : 4
    Points
    4
    Par défaut
    Merci pour ces réponses !

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

Discussions similaires

  1. Objet existant reconnu dans une fonction mais pas dans une autre
    Par Jiyuu dans le forum Général Python
    Réponses: 0
    Dernier message: 20/09/2011, 18h19
  2. Réponses: 1
    Dernier message: 26/12/2010, 21h20
  3. [Dojo] Objet Dojo créé dans une fonction et utilisé dans une autre.
    Par hapalemur dans le forum Bibliothèques & Frameworks
    Réponses: 10
    Dernier message: 05/06/2009, 13h59
  4. Réponses: 2
    Dernier message: 02/10/2008, 16h37
  5. Réponses: 2
    Dernier message: 05/03/2006, 19h29

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