2009-12-02 5 views
7

J'ai rencontré un problème que je ne comprends pas et j'espérais que quelqu'un ici pourrait nous donner un aperçu. Le code simplifié est le suivant (code d'origine était une file d'attente personnalisée/mise en œuvre de file d'attente iterator):Opérateur d'affectation par défaut en classe interne avec les membres de référence

class B 
{ 
public: 
    B() {}; 
    class C 
    { 
    public: 
     int get(); 
     C(B&b) : b(b){}; 
    private: 
     B& b; 
    }; 
public: 
    C get_c() { return C(*this); } 
}; 

int main() 
{ 
    B b; 
    B::C c = b.get_c(); 


    c = b.get_c(); 
    return EXIT_SUCCESS; 
} 

Ce, lors de la compilation, me donne l'erreur suivante:

foo.cpp: In member function 'B::C& B::C::operator=(const B::C&)': 
foo.cpp:46: error: non-static reference member 'B& B::C::b', can't use default assignment operator 
foo.cpp: In function 'int main()': 
foo.cpp:63: note: synthesized method 'B::C& B::C::operator=(const B::C&)' first required here 

Je peux contourner ce en utilisant deux variables C séparées, car elles sont censées être des objets C indépendants, mais cela ne fait que masquer le problème (je ne comprends toujours pas pourquoi je ne peux pas le faire).

Je pense que la raison est que la référence ne peut pas être copiée, mais je ne comprends pas pourquoi. Dois-je fournir mon propre opérateur d'affectation et copier le constructeur?

Répondre

13

Ce problème n'a rien à voir avec les classes internes. En C++, vous ne pouvez pas (ré) affecter des références - elles doivent être initialisées lorsqu'elles sont définies.

Un exemple plus simple est la suivante:

class B 
{ 
public: 
    B(int& i) : ir(i) {}; 

    int& ir; 
}; 


int main() 
{ 
    int i; 
    B b(i);  // Constructor - OK 

    int j; 
    B bb = B(j); // Copy constructor - OK 

    bb = b;  // Assignment - Error 
    return 0; 
} 
+0

Bah, bien sûr que vous avez raison, je ne peux pas croire que j'ai manqué l'explication évidente. Aurait dû prendre plus de café le matin: D – laura

+2

+1. Je trouve que l'habitude d'utiliser "lier" plutôt que "assigner" quand parler de références m'aide à faire cette erreur. –

+0

maintenant, je vais réaffecter une référence et bien sûr, elle va compiler: int a = 3; int b = 4; int & ref = a; ref = b ;. Il est donc possible de réaffecter une référence. – friko

6

Une référence ne peut pas être modifiée après avoir reçu sa valeur initiale. Cela signifie qu'il est impossible d'écrire un opérateur d'affectation qui modifie la valeur d'un membre de référence. Si vous avez besoin de faire cela, utilisez un pointeur au lieu d'une référence.

+0

C'est en fait possible. Vérifiez mon commentaire ci-dessous pour plus de détails. – rmn

0

C++ ne pas "classes internes", seulement des déclarations de classes imbriquées. "classes internes" sont un Java-isme que je ne pense pas que l'on trouve dans d'autres langues principales. En Java, les classes internes sont spéciales car elles contiennent une référence immuable implicite à un objet du type conteneur. Pour obtenir l'équivalent des déclarations imbriquées de C++ en Java, il faut utiliser des classes internes statiques; Les classes internes statiques ne contiennent pas de référence à un objet du type déclarant.

3

En fait, il existe une solution à cela. Vous pouvez implement operator= in terms of copy construction, et cela fonctionnera :) C'est une technique très efficace pour de tels cas. En supposant que vous voulez soutenir l'affectation.

+1

L'appel d'un destructeur dans un opérateur d'affectation est une très mauvaise habitude de programmation. – Sjoerd

+1

Tout d'abord merci pour votre réponse, j'avais atteint cette solution par moi-même mais j'ai omis le contrôle d'auto-affectation et l'appel explicite de destructeur. Vous notez que vous ne recommandez pas de l'utiliser (et je suis d'accord avec votre raisonnement), étant donné ces inconvénients, existe-t-il une implémentation préférée? – dukedave

Questions connexes