2013-10-07 24 views
17

Mam problem z odróżnieniem get i set dla operatora []. Muszę odróżnić te wywołania funkcji.Operator [] C++ Get/Set

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

Przeszukałem go, a odpowiedzi, które znalazłem, nadal nie pomogły. Ludzie sugerowali, aby podpisy dla metod różniły się poprzez dodanie stałej. Zrobiłem to i wciąż obaj nazywali tę samą metodę.

Są podpisy używałem:

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

Co robię źle?

+3

Czasami warto spojrzeć w górę * * obiekty proxy, które są często używane do rozróżnienia odczytuje z zapisów. – templatetypedef

+0

Zobacz artykuł 30 "Klasy proxy" z [Bardziej efektywne C++ autorstwa Scotta Meyersa] (http://www.amazon.com/More-Effective-Improve-Programs-ebook/dp/B004VSMDNY/ref=la_B004BBEYYW_1_2?s=books&ie= UTF8 i qid = 1381129998 & sr = 1-2) do obszernej dyskusji na ten temat, w tym zaskakujących pułapek (związanych z konwersjami zdefiniowanymi przez użytkownika), które klasy proxy mogą ci dać. Ten materiał to [obowiązkowe czytanie] (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – TemplateRex

Odpowiedz

16

Rozwiązaniem jest użycie "proxy" obiekt, który opóźni rzeczywistej operacji:

#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; 
} 

Proste const Nie można użyć opcji -ness, ponieważ może zajść potrzeba odczytu z instancji niestałej, to jest powód, dla którego musisz opóźnić operację: przypisanie odbywa się "po" dostępie, a kompilator nie powiedzieć, czy dostęp będzie później używany jako cel przydziału, czy nie.

Pomysł polega więc na tym, że po uzyskaniu dostępu przechowujesz żądany indeks i czekasz na informację, czy operacja czytania lub zapisu jest wykonywana. Dostarczając niejawnego operatora konwersji z serwera proxy do T wiesz, kiedy pojawia się operacja odczytu, dostarczając i przypisując operatorowi proxy z T wiesz, kiedy wystąpi zapis.

0

const wersję swojego operator[] zostanie wywołana na obiekcie const danych:

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

Wersja const oznacza, że ​​jeśli obiekt, na który się go nazywa, jest const, możesz wywołać tę wersję operatora [] i tylko tę wersję.

Ale jeśli obiekt nie jest const, wówczas można wywołać obie wersje operatora [], ale kompilator wybierze wersję niestałą. Innymi słowy, dla obiektu niestanowiącego stałej, niestanowiąca stałej wersji operatora może działać jako "ustawiający" lub "pobierający". Dlatego ta sama wersja jest wywoływana w obu przypadkach w twoim przykładzie, ponieważ twój obiekt data nie jest const.

Trzeba by zrobić coś takiego:

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

Aby być zgodne ze zwykłym rozumieniu indeksu operator indeks zwykle zwraca referencję do elementu, który jest naciągane. Po zwróceniu odwołania można użyć indeksu dolnego po obu stronach przydziału.

W związku z tym dobrze jest również zdefiniować wersje const i nonconst tego operatora. Po zastosowaniu do obiektu, indeks dolny powinien zwrócić odwołanie do const, aby zostało przypisane do zwróconego obiektu.

---- C++ Primer, Fifth Edition