2009-07-29 4 views
14

Ich versuche, eine Klasse mit zwei Methoden mit demselben Namen zu erstellen, um auf ein privates Mitglied zuzugreifen. Eine Methode ist public und const qualifiziert, die andere ist privat und nicht-const (wird von einer Freundesklasse verwendet, um das Mitglied über die Rückgabe durch Referenz zu ändern).private non-const und public const Mitglied Funktion - Koexistenz in Frieden?

Leider erhalte ich Kompilierfehler (mit g ++ 4.3): Wenn Sie ein nicht-konstantes Objekt verwenden, um die Methode aufzurufen, beschwert sich g ++, dass die nicht-const Version meiner Methode privat ist, obwohl eine öffentliche (const) Version existiert.

Dies scheint seltsam, denn wenn die private nicht-const-Version nicht existiert, wird alles gut kompiliert.

Gibt es eine Möglichkeit, dies zu funktionieren? Kompiliert es auf anderen Compilern?

Danke.

Beispiel:

class A 
{ 
public: 
    A(int a = 0) : a_(a) {} 
public: 
    int a() const { return a_; } 
private: 
    int & a()  { return a_; } /* Comment this out, everything works fine */ 
    friend class B; 
private: 
    int a_; 
}; 


int main() 
{ 
    A  a1; 
    A const a2; 

    cout << a1.a() << endl; /* not fine: tries to use the non-const (private) version of a() and fails */ 
    cout << a2.a() << endl; /* fine: uses the const version of a() */ 
} 
+0

Warum scheitern würde das? C++ ermöglicht die Konvertierung von nicht-const zu const, vis vis vis Funktionsparameter. – jkeys

Antwort

13

Überlastung Auflösung geschieht, bevor der Zugriff Prüfung, so dass, wenn Sie das Verfahren auf einem Nicht-const A nennen, die nicht konstante Element als eine bessere Abstimmung gewählt wird. Der Compiler schlägt aufgrund der Zugriffskontrolle fehl.

Es gibt keine Möglichkeit, "diese Arbeit zu machen", meine Empfehlung wäre, die private Funktion umzubenennen. Benötigen Sie einen privaten Accessor?

+0

Eine versteckte Klasse wäre meine beste Wette - wie die Verwendung einer Node-Struktur in einer größeren Klasse. – jkeys

+0

Das ist schade. Ich vermutete, dass dies der Fall sein würde, aber ich sehe nicht, warum es so sein muss. Hoffentlich zeigt mir jemand, warum es so sein muss, damit ich mich ausruhen kann. Der Grund, warum ich dieses Verhalten will, ist, weil ich meine Getter und Setter normalerweise als zwei const/non-const-Versionen der gleichen Methode schreibe, ohne das Präfix "get"/"set". Für diese bestimmte Klasse möchte ich keiner Klasse außer einer erlauben, die Setter zu verwenden (daher die Friend-Class-Deklaration). – mmocny

+0

Die Fähigkeit, Funktion zu überladen ist in erster Linie nützlich, wenn die Funktionen die gleiche oder ähnliche logische Operation ausführen, aber auf einem anderen Argumenttyp (besonders nützlich beim Schreiben generischen Codes in Vorlagen). Das Abrufen des Werts von etwas ist eine andere Operation als das Erhalten eines Verweises auf etwas, um es zu aktualisieren. Aus diesem Grund macht es (zumindest für mich!) Sinn, den Funktionen verschiedene Namen zu geben. Ich denke, du schwimmst gegen den Strom, wenn du versuchst, dieselben Namen zu behalten. –

2

Es wird nur die Version const ausgewählt, wenn das Objekt const deklariert ist, andernfalls wird die Version const ausgewählt (auch wenn dies zu einem Fehler führt).

sollte diese Arbeit:

cout << ((const A*)&a1)->a() << endl; 

oder dies:

A const& ra1 = a1; 
cout << ra1.a() << endl; 
+1

Ich denke, ich würde 'const_cast (a1) .a() '. Es würde ein bisschen sicherer erscheinen. –

+0

Ja, das ist das Beste Ich denke nicht, dass es sicherer ist als die zweite Methode, aber der Compiler wird die vollständige Typsicherheit für die Zuweisung zur Referenz erzwingen. Wie auch immer, ich dachte, du würdest das implementieren B. indem man die Methodensignaturen von 'A &' nach 'A const &' ändert, anstatt diese direkt zu manipulieren, wie in diesem offensichtlich konstruierten Beispiel. –

+1

Ich verstehe nicht, warum die Antwort von Charles Bailey hat eine höhere Abstimmung als diese (IMHO korrekte und funktionierende) Antwort von Tim Sylvester, die das Gegenteil von _Es gibt keine Möglichkeit, "um diese Arbeit zu machen" _. Eigentlich kam ich hierher, weil ich wusste, dass ich so Ich habe ein solches Problem irgendwo in meinem Code gespeichert, aber ich habe vergessen, wo und wie. (Btw. Ich habe es genau so gelöst, wie oben beschrieben. Vielleicht sollte ich versuchen, beim nächsten Mal auf meinen eigenen lokalen Quelltext zu googeln ...) – Scheff