Ein bisschen ausführlicher als Meyers, aber ich könnte das tun:
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); }
};
Die private Methode hat die unerwünschte Eigenschaft, dass sie ein nicht-const Z & für eine const-Instanz zurückgibt, weshalb sie privat ist. Private Methoden können Invarianten der externen Schnittstelle aufbrechen (in diesem Fall ist die gewünschte Invariante "ein const-Objekt kann nicht über Verweise auf Objekte geändert werden, die es hat-a").
Beachten Sie, dass die Kommentare Teil des Musters sind - die Benutzeroberfläche von _getZ gibt an, dass es niemals gültig ist, sie aufzurufen (abgesehen von den Accessoren natürlich): Es ist ohnehin kein denkbarer Vorteil, dies zu tun, da 1 Zeichen mehr eingegeben werden muss und nicht führen zu kleinerem oder schnellerem Code. Das Aufrufen der Methode entspricht dem Aufrufen eines der Accessoren mit einem const_cast, und das möchten Sie auch nicht. Wenn Sie sich Sorgen machen, Fehler offensichtlich zu machen (und das ist ein faires Ziel), nennen Sie es const_cast_getZ anstelle von _getZ.
Ich schätze übrigens Meyers Lösung. Ich habe keine philosophischen Einwände dagegen. Persönlich bevorzuge ich jedoch ein kleines Stück kontrollierter Wiederholung und eine private Methode, die nur unter bestimmten streng kontrollierten Umständen aufgerufen werden darf, gegenüber einer Methode, die wie Linienrauschen aussieht. Wählen Sie Ihr Gift und bleiben Sie dabei.
[Bearbeiten: Kevin hat zu Recht darauf hingewiesen, dass _getZ möglicherweise eine weitere Methode (z. B. generateZ) aufrufen möchte, die auf die gleiche Weise wie getZ auf const spezialisiert ist. In diesem Fall würde _getZ ein const Z & sehen und müsste es vor der Rückkehr const_cast. Das ist immer noch sicher, da der Boilerplate-Zubehör alles überwacht, aber es ist nicht besonders offensichtlich, dass es sicher ist. Wenn Sie dies tun und später generateZ ändern, um immer const zurückzugeben, müssen Sie außerdem getZ ändern, um immer const zurückzugeben, aber der Compiler sagt Ihnen nicht, dass Sie dies tun.
Dieser letztere Punkt über den Compiler gilt auch für Meyers empfohlenes Muster, der erste Punkt über einen nicht offensichtlichen const_cast jedoch nicht. Alles in allem denke ich, dass, wenn sich herausstellt, dass _getZ einen const_cast für seinen Rückgabewert benötigt, dieses Muster einen großen Teil seines Wertes gegenüber Meyers verliert. Da es auch Nachteile gegenüber Meyers hat, denke ich, dass ich in dieser Situation zu seinem wechseln würde. Das Refactoring von einem zum anderen ist einfach - es wirkt sich nicht auf anderen gültigen Code in der Klasse aus, da nur ungültiger Code und das Boilerplate _getZ aufrufen.]