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

C++ Discussion :

surcharge operator=, héritage et fonction virtuelle pure


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite Avatar de mchk0123
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    816
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 816
    Par défaut surcharge operator=, héritage et fonction virtuelle pure
    Le code suivant précise dans la classe mère que l'operateur '=' doit être surchargé dans la classe fille. Or dès utilisation dans le main, il semblerait que l'aspect 'virtuel' de la surcharge ne fonctionne pas et qu'il cherche à appeller l'opérateur de la classe mère (non implémenté) plutôt que sa ré-écriture dans la classe fille !

    Bref, je comprend vraiment pas là ou j'ai faux :

    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
    #include <cstdlib>
    #include <cstdio>
    #include <ctime>
     
    class a {
      public:
        a();
        //virtual a& operator=(const a &ref) = 0;
        virtual a& set(const a &ref) = 0;
        void print() const;
      protected:
        int x;
    };
     
    class b : public a{
      public:
        //a& operator=(const a &ref);
        a& set(const a &ref);
    };
     
    a::a() {
      srand(time(NULL));
      x = rand();
    }
    void a::print() const {
      printf("x = %d\n", x);
    }
     
    /*
    a& b::operator=(const a &ref) {
      x = dynamic_cast<const b*>(&ref)->x;
     
      return *this;
    }
    */
    a& b::set(const a &ref) {
      x = dynamic_cast<const b*>(&ref)->x;
     
      return *this;
    }
     
    int main() {
      b x, y;
     
      x.print();
      //y = x;
      y.set(x);
      y.print();
     
      return 0;
    }
    Message d'erreur lors de l'édition de liens :

    main.o:main.cpp: (.text$_ZN1baSERKS_[b::operator=(b const&)]+0x14): undefined reference to `a::operator=(a const&)'
    collect2: ld returned 1 exit status
    Si j'utilise à la place de l'opérateur '=', la fonction 'set' la compilation passe bien.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Salut,

    Mais pourquoi voudrais tu donc fournir l'opérateur d'affectation en tant que fonction virtuelle pure

    Typiquement, une fonction virtuelle pure, c'est une fonction pour laquelle on ne dispose pas des informations nécessaire à sa définition...

    Or, tu dispose de toutes les informations pour te permettre de définir l'opérateur d'affectation... il n'y a donc a priori aucune raison qu'il ne soit virtuel pur

    De plus, rien ne t'empeche de déclarer une fonction virtuelle pure, mais de la définir avec un comportement par défaut, justement dans le cas où une classe dérivée venait à ne pas la réimplémenter

    Enfin, si ton seul but est de créer une classe non instanciable, tu peux toujours placer les constructeurs en acces protected, et implémenter l'ensemble des fonctions qui n'auraient pas lieu d'etre virtuelles pures

    Et, petite remarque en passant: tu aurais largement intéret à utiliser std::cout<< pour l'affichage, plutot que le printf() qui vient du C
    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
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 633
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Je voudrais rajouter que, si ton but est d'empecher l'utilisation de l'opérateur d'affectation au profit de la fonction set(), rien ne t'empeche de le déclarer en visibilité private, mais de le déclarer...

    Et le fait que l'opérateur d'affectation doit, normalement, renvoyer une référence du type de l'objet passé...

    tu auras
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    a& operator(const a& ref);
    dans la classe a et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    b& operator(const b& ref);
    dans la classe b

    Si, plus loin tu veux faire un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    b bb;
    a aa=bb;//meme pas sur que cela compile, ceci dit :P
    cela se fait automatiquement, étant donné que tout b est un a, du fait de l'héritage

    [EDIT]ainsi que le fait que, si tu n'utilise pas des pointeurs au sein d'une classe, tu peux tres bien laisser le compilateur placer lui-meme le constructeur par copie et l'opérateur d'affectation... si, du moins, cela ne t'embete pas qu'ils soient en visibilité publique
    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

  4. #4
    Membre émérite Avatar de mchk0123
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    816
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 816
    Par défaut
    Merci de tes réponses koala.

    Voilà quelques petites précisons concernant ce que je voulais faire :

    - l'exemple de code que j'ai mis est un framework de collaboration entre classes
    - la classe a est uniquement une "interface"
    - elle ne possède que des méthodes virtuelles pures afin d'obliger les classes déscendante à implémenter chaque fonction de l'interface (sinon ça ne passe pas à la compilation)
    - cela sert également comme aide mémoire lors de l'extension du framework

    Donc la méthode virtuelle pure "operator=" est là dans a, uniquement pour forcer l'implémentation de la surcharge de cet opérateur dans b.

    Seulement voilà cette pratique trés propre au niveau de la conception se révèle délicate dans le cas de l'opérateur "=" puisque, comme tu l'as dit, chaque opérateur doit travailler sur la classe qui le définit. Donc typiquement on devrait avoir :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    a& a::operator=(const a &ref) {
    ...
    b& b::operator=(const b &ref) {
    ...
    Mais en faisant ça je perds 2 choses :
    - la capacité dans la classe mère a d'appeller l'opérateur virtuel "="
    - la notification par message d'erreur à la compilation dans le cas ou
    l'opérateur n'est pas surchargé dans b

    Donc je suis confronté à un dilemme :
    1. Se conformer à la notion d'interface virtuelle pure => pb : ne passe pas à la compilation
    2. Se conformer à la syntaxe de la surcharge de l'opérateur "=" => pb : voir les 2 ci-dessus

    Donc ma question est, dans la pratique, comment habituellement gérez-vous ce genre de situation ?

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 633
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Cela ne me pose aucun problème de conscience que de laisser à l'utilisateur le choix d'implémenter ou non son propre opérateur d'affectation...

    Surtout qu'à bien y réfléchir, le compilateur est parfaitement capable d'en fournir un tout à fait efficace, tant que l'on n'est pas dans le cadre d'une classe dont le constrcteur est du genre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Maclass::Maclass(/*...*/)
    {
        ptr=new type;
    }
    ou approchant...

    Par contre, ce qui peut s'avérer intéressant, c'est peut etre, ainsi que je te l'ai signalé plus haut, de faire passer le constructeur par copie et l'opérateur d'affectation dans une visibilité différente que la visibilité publique...

    Je le verrais bien dans une visibilité protected, histoire que seules les classes qui dépendent de l'interface puisse y accéder
    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

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 391
    Par défaut
    mchk0123 : Comme dit chez GotW, le mieux est de séparer l'interface virtuelle de l'implémentation.
    En clair, à ta place, je ferais ceci:
    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
    26
    27
    28
    29
    30
    31
    class a
    {
    public:
        //Opérateur d'affectation non-virtuel
        a & operator=(a const & src)
        { VSet(src); return *this; }
    protected:
        //Fonction d'affectation virtuelle privée
        //(enfin, protected, car elle doit appeler celle de la classe mère)
        virtual void VSet(a const & src);
    };
     
    class b
    {
    protected:
        //Fonction d'affectation virtuelle privée
        //(enfin, protected, car elle doit appeler celle de la classe mère)
        virtual void VSet(a const & src);
    };
     
    void a::VSet(a const & src)
    {
        //...
    }
     
    void b::VSet(const a & src)
    {
        a::VSet(src);
        b const * pcB = static_cast< b const * >( &src );
        //...
    }
    Je n'ai pas essayé de compiler, mais c'est l'idée générale.
    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. Surcharge de fonction virtuelle pure
    Par lg_53 dans le forum C++
    Réponses: 4
    Dernier message: 07/11/2014, 15h26
  2. fonction virtuel pure et constante
    Par ZaaN dans le forum C++
    Réponses: 5
    Dernier message: 03/08/2007, 15h27
  3. Réponses: 2
    Dernier message: 30/01/2007, 11h44
  4. Réponses: 2
    Dernier message: 05/03/2006, 19h29
  5. Compilation avec des fonctions virtuel pure
    Par vanitom dans le forum C++
    Réponses: 4
    Dernier message: 16/12/2005, 14h37

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