2013-10-07 13 views
17

Ich habe Probleme mit dem Unterschied zwischen Get und für den Operator []. Ich muss den Unterschied zwischen diesen Funktionsaufrufen unterscheiden.Operator [] C++ Holen/Setzen

cout << data[5]; 
data[5] = 1; 

Ich googeln es, und die Antworten, die ich immer noch nicht helfen gefunden. Die Leute schlugen vor, die Signaturen für die Methoden anders zu machen, indem sie const hinzufügen. Ich tat das, und sie riefen immer noch die gleiche Methode an.

Es sind die Unterschriften ich benutzt hatte:

const T& operator[](unsigned int index) const; 
T& operator[](unsigned int index); 

Was mache ich falsch?

+3

Vielleicht möchten Sie * Proxy-Objekte sehen *, die oft von Schreiben liest, zu unterscheiden, verwendet. – templatetypedef

+0

Siehe Punkt 30 "Proxy-Klassen" aus [Effektiver C++ von Scott Meyers] (http://www.amazon.com/More-Effective-Improve-Programs-ebook/dp/B004VSMDNY/ref=la_B004BBEYYW_1_2?s=books&ie= UTF8 & qid = 1381129998 & sr = 1-2) für eine ausführliche Diskussion zu diesem Thema, einschließlich überraschender Fallstricke (im Zusammenhang mit benutzerdefinierten Conversions), die Proxy-Klassen Ihnen geben können. Dieses Material ist [Pflichtlektüre] (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – TemplateRex

Antwort

16

Die Lösung ist ein "Proxy" Objekt zu verwenden, die den eigentlichen Betrieb verzögern:

#include <vector> 
#include <iostream> 

template<typename T> 
struct MyArray { 
    std::vector<T> data; 
    MyArray(int size) : data(size) {} 

    struct Deref { 
     MyArray& a; 
     int index; 
     Deref(MyArray& a, int index) : a(a), index(index) {} 

     operator T() { 
      std::cout << "reading\n"; return a.data[index]; 
     } 

     T& operator=(const T& other) { 
      std::cout << "writing\n"; return a.data[index] = other; 
     } 
    }; 

    Deref operator[](int index) { 
     return Deref(*this, index); 
    } 
}; 

int main(int argc, const char *argv[]) { 
    MyArray<int> foo(3); 
    foo[1] = 42; 
    std::cout << "Value is " << foo[1] << "\n"; 
    return 0; 
} 

Einfache const -ness kann nicht verwendet werden, weil Sie möglicherweise von einer nichtkonstanten Instanz lesen müssen, weshalb Sie die Operation verzögern müssen: Die Zuweisung erfolgt "nach" dem Zugriff und der Compiler nicht sagen Sie, ob der Zugriff später als Ziel für die Zuweisung verwendet wird oder nicht.

Die Idee ist also, dass Sie bei Zugriff nur den Index, der angefordert wurde, speichern und warten, um zu wissen, ob ein Lese- oder Schreibvorgang stattfindet. Durch die Bereitstellung eines impliziten Konvertierungsoperators vom Proxy zu T wissen Sie, wann eine Leseoperation stattfindet, indem Sie dem Proxy von T einen Operator zur Verfügung stellen und ihn zuweisen, den Sie wissen, wenn das Schreiben erfolgt.

0

const Version Ihrer operator[] für const Datenobjekt aufgerufen werden:

const Data data; 
cout << data[5]; 
3

Die Version bedeutet, dass, wenn das Objekt, auf dem es aufgerufen wird, const ist, dürfen Sie diese Version des []-Operators und nur diese Version aufrufen.

Wenn das Objekt jedoch nicht const ist, können beide Versionen des Operators [] aufgerufen werden, aber der Compiler wählt die nicht-const-Version aus. Mit anderen Worten, für ein nicht-konstantes Objekt kann die nicht-konstante Version des Operators entweder als "Setzer" oder "Getter" fungieren. Daher wird in beiden Fällen in Ihrem Beispiel dieselbe Version aufgerufen, da Ihr data Objekt nicht const ist.

Sie würden, so etwas zu tun haben:

const Data& data_cref = data; 
cout << data_cref[5]; // calls the const version of operator[] 

Data& data_ref = data; 
data_ref[5] = 1;  // calls the non-const version of operator[] 
1

Um mit der gewöhnlichen Bedeutung des Index kompatibel zu sein, gibt der Index-Operator in der Regel einen Verweis auf das Element, das abgerufen wird. Durch das Zurückgeben einer Referenz kann der Index auf jeder Seite einer Zuweisung verwendet werden.

Daher ist es normalerweise auch eine gute Idee, sowohl const als auch nonconst Versionen dieses Operators zu definieren. Wenn er auf ein Objekt angewendet wird, sollte der Index einen Verweis auf const zurückgeben, damit er dem zurückgegebenen Objekt zugewiesen wird.

---- C++ Primer, fünfte Ausgabe