2011-02-10 3 views
15
class Foo 
{ 
    int Bar; 

    public: 

    int& GetBar() const 
    { 
     return Bar; 
    } 
} 

Est-il correct que GetBar est une méthode const? Cela ne change rien, mais c'est un moyen de changer le monde extérieur.Const méthodes qui retournent des références

+0

Je pense que vous avez déjà répondu à votre question. De plus, dans l'exemple Bar est déjà public. – XAder

+0

'& Bar' a le type' const int * ', pas' int & '. Votre compilateur devrait vous dire que ce n'est pas OK. –

+0

Avez-vous essayé de compiler? Qu'est-ce que le compilateur vous a dit? –

Répondre

18

Vous avez une erreur dans votre code, c'est ce que vous vouliez probablement dire:

class Foo 
{ 
    int Bar; 

    public: 

    int& GetBar() const 
    { 
     return Bar; // Removed the ampersand, because a reference is returned, not an address 
    } 
} 

Et non, ce n'est pas légal .Lorsque vous étiquetez une méthode avec const, non seulement vous promettez de ne pas toucher à l'état interne de l'objet, mais vous promettez également de ne rien retourner qui puisse être utilisé pour changer l'état de l'objet. Une référence non-const peut être utilisée pour modifier la valeur de Bar en dehors de la portée de GetBar(), ce qui implique que vous ne pouvez pas tenir la promesse.

Vous devez soit remplacer la méthode par const, renvoyer une référence const, soit Bar par exempter la promesse en l'appelant mutable. Exemple: mutable int Bar; Le mot-clé mutable indique au compilateur que la constance logique de l'objet ne dépend pas de l'état Bar. Ensuite, vous êtes autorisé à faire ce que vous voulez.

4

Nope, puisque vous ne pouvez pas faire l'affectation suivante: const int x; int &y = x;

Ce que vous pouvez faire bien est const int x; const int &y = x;

Et bien sûr, il n'y a pas de problème à surcharger la méthode et créer à la fois const et non-const variantes.

3

Vous souhaitez probablement renvoyer Bar, et non &Bar. Quoi qu'il en soit, je laissai tomber ce code dans Comeau:

class Foo 
{ 
    int Bar; 

    public: 

    int& GetBar() const 
    { 
     return &Bar; 
    } 
}; 

int main(int argc, char** argv) 
{ 
    Foo x; 
    int y = x.GetBar(); 
    y = 5; 
    return 0; 
} 

et a obtenu l'erreur:

line 9: error: qualifiers dropped in binding reference of type 
      "int &" to initializer of type "const int" 
      return Bar; 
       ^
1

Tout d'abord, pour retourner une référence que vous n'avez pas besoin d'utiliser l'opérateur esperluette sur l'objet référencé ; il est nécessaire si vous voulez obtenir un pointeur. Donc, je suppose que vous vouliez écrire return Bar;.

Ensuite, non, vous ne pouvez pas faire cela; dans une méthode const vous avez un pointeur constthis (dans votre cas, il serait un const Foo *), ce qui signifie que toute référence vous pouvez accéder à ses champs sera une référence const, puisque vous y accéder par un " const chemin ". Donc, si vous essayez de faire ce que vous avez fait dans ce code, vous obtiendrez une erreur de compilation, puisque vous essayez d'initialiser un int & (la valeur de retour de votre méthode) avec un const int & (la référence obtenir de Bar), ce qui est évidemment interdit.

g ++ dit en fait:

testconstref.cpp: In member function ‘int& Foo::GetBar() const’: 
testconstref.cpp:9: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘const int*’ 

qui est ce que je viens de dire. Si vous renvoyez une référence const à un champ de classe à partir d'une méthode const, vous n'aurez aucun problème.


  1. Hors champs marqués comme mutable, qui indique au compilateur que ces champs sont modifiables même de const méthodes; cette exception a été introduite pour permettre aux méthodes const de changer l'état "réel" de l'objet dans les cas où cela ne modifie pas son état "logique"; cela peut être utile pour mettre en œuvre l'évaluation paresseuse, comptage de référence, ...
0

const Le modificateur d'une fonction membre ne permet pas de modifier l'état de l'objet dans sa portée. Le compilateur vérifie simplement si cette fonction modifie l'état de l'objet ou pas dans sa portée. Autre exemple -

class foo 
{ 
    int num ; 
    public : 
     foo(int anum) 
     { 
      anum = 10; 
     } 
     int getNum() 
     { 
      return num; 
     } 
}; 

foo obj; 
int& myNum = obj.getNum() ; // myNum is just an alias to the private class variable num 
myNum = 40; // Actually changes the content of the private variable. 

Ainsi, le compilateur ne vérifie que spécificateurs d'accès (à savoir si cette variable est accessible ou non dans ce cadre), mais pas sur l'emplacement de mémoire du privé/public/variables protégées en cas de retour à une autre variable .

1

Les membres de votre classe sont considérés const quand vous êtes dans une méthode const. Donc bien que Bar soit int dans votre classe et non const int, dans le contexte de GetBar() const c'est "const int". le renvoyer donc comme une référence non-const ou pointeur est tout aussi illégal que faire:

const int y = 57; int& z = y;

Ce casse-const correct, même si la 2ème ligne n'a pas changé quoi que ce soit (encore) en y. Notez par ailleurs que si votre classe a des membres de pointeur, la seule chose qui est const est les pointeurs eux-mêmes et non ce qu'ils pointent vers. (Souvent appelée « superficielle » constness)

Ainsi, ce serait légal:

class A 
{ 
    Foo * foo; 

    public: 
    Foo * getFoo() const // legal. does not have to return const Foo * 
    { 
     return foo; 
    } 
}; 

Notez que dans votre code original que vous puissiez revenir Bar par référence non-const si elle était mutable, parce que ces membres ne sont pas liés par la constance des fonctions membres.

Questions connexes