2010-09-16 26 views
2

J'ai rencontré le problème suivant qui m'a prouvé que j'en connais trop peu sur le fonctionnement de C++.Les opérateurs d'affectation ne sont-ils pas surchargés lorsqu'ils sont appelés sur des pointeurs d'une classe de base?

-je utiliser une classe de base avec des fonctions virtuelles pures

class Base 
    ... 

et une classes dérivées de type

class Derived : public Base{ 
private: 
    Foo* f1; 
... 

ont tous deux opérateurs d'affectation mis en œuvre. Entre autres choses, l'opérateur d'affectation de Derived copie les données dans f1. Dans mon code, je crée deux nouvelles instances de classe dérivée

Base* d1 = new Derived(); 
Base* d2 = new Derived(); 

Si je l'appelle maintenant l'opérateur d'affectation

*d1 = *d2; 

l'opérateur d'affectation des dérivées n'est pas appelée, et les données f1 ne sont pas copiées ! Cela ne fonctionne que si je le fais

*dynamic_cast<Derived*>(d1) = *dynamic_cast<Derived*>(d2); 

Quelqu'un peut-il expliquer pourquoi les opérateurs d'affectation ne sont pas surchargés?

Merci!

+1

Vous n'avez pas de classe de base virtuelle; si 'Base' était une classe de base virtuelle,' Derived' serait déclaré comme 'classe Derived: public virtual Base'. Votre classe de base peut avoir des fonctions virtuelles. –

+0

Je pense que vous surchargez et surchargez. – fredoverflow

Répondre

4

Il est difficile de dire sans voir le code pertinent. Voici un exemple qui fonctionne:

#include <iostream> 

using namespace std; 

class A { 
    public: 
    virtual A& operator=(A& a) {} 
}; 

class B : public A { 
    public: 
    B& operator=(A& a) { cout << "B" << endl; } 
}; 

int main() { 
    A* foo = new B(); 
    A* bar = new B(); 
    *foo = *bar; 
    return 0; 
} 

Cette imprimera B lors de son exécution.

choses que vous pourriez faire mal:

  1. Vous pourriez avoir oublié de faire operator= virtuelle dans la classe de base.
  2. Vous avez peut-être donné la classe de l'enfant operator= comme signature plus restrictive que celle du operator= du parent, vous ne remplacez donc pas la définition du parent. Par exemple, si vous changez B& operator=(A& a) { cout << "B" << endl; } en B& operator=(B& a) { cout << "B" << endl; } dans l'exemple ci-dessus, il n'imprimera plus B.
1

Pour que le travail virtuel ait besoin de la même signature. Donc, si votre operator= fonctionne sur un paramètre const Derived& dans votre classe Derived qui ne correspond pas à celui qui fonctionne sur un paramètre const Base& dans votre classe de base. Cela signifie que vous pouvez accomplir le polymorphisme mais vous devez avoir un operator=(const Base&) dans votre classe dérivée pour le faire.

+0

Est-il permis d'avoir les deux opérateurs operator = (const Derived &) et operator = (const Base &)? – Hans

+0

@Hans: Oui, ça va. –

3

J'ai une autre perspective sur la réponse acceptée. C'est essentiellement More Effetive C++ Point 33. Donc, même si la solution acceptée fonctionne, je pense qu'il est important de faire ressortir les dangers liés à la réalisation de l'opérateur d'affectation virtuelle!

class Animal { 
public: 
    virtual Animal& operator=(const Animal& rhs); 
}; 

class Lizard: public Animal { 
public: 
    virtual Lizard& operator=(const Animal& rhs); 
}; 

class Chicken: public Animal { 
public: 
    virtual Chicken& operator=(const Animal& rhs); 
}; 

int main(){ 
    Lizard l; 
    Chicken c; 

    Animal *pL = &l; 
    Animal *pC = &c; 

    *pL = *pC;    // assigns chicken to a lizard. 
}