2014-05-02 2 views
10

Ce qui suit sera compile même si une fonction membre const modifie la valeur d'un membre. Comment ?Pourquoi les membres de référence peuvent-ils être modifiés par des fonctions membres const?

#include <iostream> 

struct foo 
{ 
    std::string &str; 
    foo(std::string &other) : str(other) {} 

    void operator()(std::string &some) const 
    { 
     str += some; 
    } 
}; 

int main() 
{ 
    std::string ext("Hello"); 
    foo a{ ext }; 

    std::string more(" world!"); 
    a(more); 

    cout << a.str; 
    return 0; 
} 
+5

Il modifie ce à quoi le membre se réfère, il ne modifie pas le membre. –

+2

Parce qu'il ne modifiera pas la référence elle-même. Après avoir appliqué l'opérateur '+ =', la référence ne change pas, seul le contenu de la chaîne interne le fait (dans le contexte de la chaîne, 'this' est toujours le même). –

+0

Essayez-le avec std :: string * au lieu de & et vous verrez la même chose. – dlf

Répondre

1

Le qualificatif const d'une fonction de membre de la classe indique que cette fonction membre (par exemple, foo::operator() const) ne peut pas changer l'état de l'objet à partir du point de client de vue (à savoir, son état abstrait). Ce n'est pas exactement la même chose que de dire que les bits bruts de l'objet ne vont pas changer.

Il est prévu que les compilateurs C++ considèrent les objets comme des bits bruts, sauf s'ils peuvent résoudre the problem of aliasing. ce qui dans votre cas, le compilateur ne peut pas. Ceci est dû au fait qu'un alias non constant existe (c'est-à-dire, std::string &str) et par conséquent l'état de l'objet est modifiable.

C'est, appelant operator() sur l'objet a ne change pas l'état de a (à savoir, bien que ext a changé, le str reste encore un alias de ext). Ce qui précède explique aussi pourquoi pointer un objet avec un pointeur vers une constante (c'est-à-dire std::string * const str) ne garantit pas que l'objet ne sera pas modifié. Cela garantit seulement que l'objet ne changera pas à travers ce pointeur.

11

Tenir compte de la référence comme un pointeur classique:

#include <iostream> 

struct foo 
{ 
    std::string * const str; // is the same as std::string &str 
    foo(std::string &other) : str(&other) {} 

    void operator()(std::string &some) const 
    { 
     *str += some; 
    } 
}; 

int main() 
{ 
    std::string ext("Hello"); 
    foo a{ ext }; 

    std::string more(" world!"); 
    a(more); 

    cout << a.str; 
    return 0; 
} 

Vous verrez que le pointeur ne change pas, seule la valeur pointée par ce fait.

Questions connexes