Un peu plus verbeux que Meyers, mais je pourrais faire ceci:
class X {
private:
// This method MUST NOT be called except from boilerplate accessors.
Z &_getZ(size_t index) const {
return something;
}
// boilerplate accessors
public:
Z &getZ(size_t index) { return _getZ(index); }
const Z &getZ(size_t index) const { return _getZ(index); }
};
La méthode private a la propriété indésirable de renvoyer un Z & non const pour une instance const, c'est pourquoi elle est privée. Les méthodes privées peuvent casser les invariants de l'interface externe (dans ce cas, l'invariant souhaité est "un objet const ne peut pas être modifié via des références obtenues via lui vers les objets qu'il a-a").
Notez que les commentaires font partie du modèle - l'interface de _getZ spécifie qu'il n'est jamais valide de l'appeler (à part les accesseurs, évidemment): il n'y a aucun avantage concevable à le faire de toute façon, car c'est un caractère de plus à taper et ne le fera pas entraîner un code plus petit ou plus rapide. Appeler la méthode équivaut à appeler l'un des accesseurs avec un const_cast, et vous ne voudriez pas le faire non plus. Si vous craignez de rendre les erreurs évidentes (et c'est un objectif équitable), appelez-le const_cast_getZ au lieu de _getZ.
Soit dit en passant, j'apprécie la solution de Meyers. Je n'ai aucune objection philosophique à lui. Personnellement, cependant, je préfère un tout petit peu de répétition contrôlée et une méthode privée qui ne doit être appelée que dans certaines circonstances étroitement contrôlées, plutôt qu'une méthode qui ressemble à du bruit de ligne. Choisissez votre poison et respectez-le.
[Edit: Kevin a souligné à juste titre que _getZ pourrait vouloir appeler une autre méthode (disons generateZ) qui est const-spécialisée de la même manière que getZ. Dans ce cas, _getZ verrait un const Z & et devrait le const_cast avant de revenir. C'est toujours sûr, car l'accessoire passe-partout règle tout, mais il n'est pas extrêmement évident qu'il soit sûr. De plus, si vous faites cela et que vous modifiez ensuite generateZ pour toujours retourner const, vous devez également changer getZ pour toujours retourner const, mais le compilateur ne vous le dira pas.
Ce dernier point sur le compilateur est également vrai pour le modèle recommandé par Meyers, mais le premier point sur un const_cast non évident ne l'est pas. Donc, tout compte fait, je pense que si _getZ s'avère avoir besoin d'un const_cast pour sa valeur de retour, alors ce modèle perd beaucoup de sa valeur par rapport à Meyers. Puisqu'il souffre également d'inconvénients par rapport à Meyers, je pense que je passerais au sien dans cette situation. La refactorisation de l'un à l'autre est facile - elle n'affecte aucun autre code valide de la classe, car seul le code non valide et le passe-partout appellent _getZ.]