jezyki_i_techniki_programowania:przeladowanie_operatorow [mgr Wiki]

[[jezyki_i_techniki_programowania:przeladowanie_operatorow]]
mgr Wiki

# Przeładowanie operatorów ( C++ )

Przeładowanie operatorów w klasie sprawia, że posługiwanie się nią jest tak naturalne jak typem wbudowanym.

Przeładowanie operatora dokonuje się definiując funkcję która

- nazywa się operator@ gdzie @ oznacza symbol operatora (np +, -, *)
- jako conajmniej jeden z argumentów przyjmuje obiekt danej klasy (nie wskaźnik)

# Nie można przeładowywać

- . odniesienie do składnika klasy
- .* wybór składnika wskaźnikiem
- :: określenie zakresu

Do grupy tej można jeszcze dodać operator ?:

# O czym należy pamiętać

- nie wolno wymyślać operatorów
- nie można zmieniać ustalonych priorytetów, łączności oraz argumentowości
- przynajmniej jeden z argumentów operatora musi być typu zdefiniowanego przez programistę

Ten sam operator można przeładowywać wielokrotnie (podobnie jak funkcję) zmieniając zestaw argumentów na których operuje.

# Sposoby przeciążenia

Operator (funkcja operatorowa) może być zdefiniowany jako

- niestatyczna funkcja składowa klasy
- funkcja globalna

Aby umożliwić operatorowi dostęp zarówno do publicznych jak i prywatnych składowych klasy musi on zostać zdefiniowany jako funkcja składowa lub globalna funkcja zaprzyjaźniona z klasą.

Następujące operatory musza zostać zdefiniowane jako niestatyczne funkcje składowe:

= [] () →

# Operatory generowane automatycznie

Operatory generowane automatycznie dla każdej klasy: = & , new delete

Jeśli operator ma wykonywać akcję inna niż predefiniowana, należy zdefiniować własną wersję tego operatora.

Operator = nie bedzie generowany automatycznie w klasie jesli:

- posiada ona składnik const lub składnik będący referencją
- klasa posiada składową będącą obiektem innej klasy w której operator = jest private
- klasa dziedziczy z klasy w której operator = jest typu private

# Wyjątkowy operator

Operatory inkrementacji (dekrementacji).

Mimo, że są to operatory jednoargumentowe, możliwa jest również ich definicja jako operatorów dwuargumentowych (próba definicji operatora jednoargumentowego np. ! jako dwuargumentowego byłaby błędem).

       obiekt.operator++() 	//pre-inkrementacja
       obiekt.operator++(0)	//post-inkrementacja

# Uwagi

Jeśli przeładowano operator + i = nie oznacza to, że dostępne są operatory += albo ++. Są to zupełnie inne funkcje operatorowe i muszą zostać zdefiniowane osobno.

Jeśli dla typów wbudowanych poniższe wyrażenia są równoważne

    a = a + 1	a +=1	a++

to dobrą praktyką jest trzymanie sie tej konwencji w definiowanych klasach.

Jeśli operator nie zmienia wartości typu wbudowanego, nie powinien też modyfikować wartości obiektów klasy dla której został przeładowany (np. operator -).

Przeładowywany operator powinien zwracać wartość. Dzieki temu możliwe będzie budowanie wyrażeń kaskadowych.

Jeśli operator zmienia w jakiś sposócb obiekt, na którym pracuje to powinien być zdefiniowany jako funkcja składowa klasy (zwracająca l-wartość). W przeciwnym wypadku (brak modyfikacji składowych obiektu) stosuje się raczej operator w postaci funkcji globalnej.

# Przykład praktycznego zastosowania przeładowania operatora

Rozważmy zapis:

        int i = 19;
        cout << i;

Dlaczego ten zapis powoduje wyprowadzenie na ekran wartości zmiennej i (dwuargumentowy operator « dla typu wbudowanego int jest operatorem przesunięcia bitów) ?

Mamy tu doczynienia z przeładowaniem operatora « w klasie ostream. Oczywiście jest kilka wersji przeładowania operatora « na okoliczność pracy z różnymi typami argumentów np. float, char*. Dzięki temu że funkcja operatorowa nie musi być zaprzyjaźniona z klasą można zdefiniować koleją wersję operatora «, w której pierwszym argumentem jest obiekt klasy ostream (brak jednak dostępu do niepublicznych składników), a drugim obiekt definiowanej klasy.

Funkcja ta nie może być funkcją składową klasy ostream, ponieważ nie można modyfikowac wnętrza klas bibliotecznych.

Są więc dwie inne możliwości realizacji tego zadania:

- funkcja globalna
- funkcja składowa definiowanej klasy

Ponieważ zapis

        w << cout;

wyglada bardzo dziwacznie ta druga możliwość odpada.

Jeśli definiując funkcję operatorową « jako funkcję globalną wymagany jest dostęp do niepublicznych składowych klasy, musi ona zadeklarować przyjaźń z naszą funkcją operatorową.

## Linki

- http://nauka-programowania.pl/O2.PDF

jezyki_i_techniki_programowania/przeladowanie_operatorow.txt · Last modified: 2006/05/21 15:09 by 83.18.177.219