Krzysztof Wesołowski » przeciazanie http://kwesoly.net Programowanie, elektronika, automatyka - doświadczenia i projekty Wed, 07 Sep 2011 14:03:29 +0000 pl-PL hourly 1 Przeładowanie operatorów cześć 1. http://kwesoly.net/programowanie/cpp/przeladowanie-operatorow-1/ http://kwesoly.net/programowanie/cpp/przeladowanie-operatorow-1/#comments Mon, 14 Jul 2008 10:41:04 +0000 http://kwesoly.hekko.pl/wordpress/?p=4 Słowem wstępu

Postaram się opisać na podstawie już wcześniej stworzonego programu (operacja na wektorach) jak przeładowywać w C++ podstawowe operatory.

Postaram się skupić na samym przeładowaniu, bez wchodzenia w szczegóły samego działania.

Operatory powinno się przeładowywać właśnie tam, gdzie ich działanie jest jednoznaczne na pierwszy rzut oka: działania arytmetyczne, operatory wejścia, wyjścia i inne, rzadziej używane o których wspomnę innym razem.

Ogólną ideą która powinna przyświecać przeładowywaniu to tworzenie przewidywalnych, zachowujących się analogicznie jak te wbudowane operatorów.

Przeładowany operator to po prostu funkcja o nazwie operator z dopisaną końcówką charakteryzującą operator, np operator+, operator*= etc. Samą funkcje można zdefiniować na dwa sposoby:

  1. Jako funkcje składową klasy
    wtedy napisanie obiekt1+obiekt2 oznacza wywołanie: obiekt1.operator+(obiekt2)
  2. Jako funkcje globalną
    wtedy napisanie obiekt1+obiekt2 oznacza wywołanie: operator+(obiekt1,obiekt2)

Operatory dodawania

Występuje w kilku wariacjach:

Zwykły operator dodawania:

Założenia:

  1. Dodaje elementy tego samego/podobnego typu do siebie
  2. Nie zmienia żadnego z elementów (żeby działało na obiektach stałych tak jak 2+5)
  3. Wynik powinien być zwrócony przez wartość (gdyż obiekty wewnątrz funkcji utworzone mogą zostać zniszczone już po jej zakończeniu)

Przykład:

Listing:
  1. class Vector {
  2. ...
  3. public:
  4. Vector         operator+(const Vector& rhs)    const;
  5. ...
  6. }
Listing:
  1. Vector         operator+(const Vector& lhs,const Vector& rhs);

Obie metody działają, natomiast zdecydowanie elegantsza wydaje się dla mnie być ta pierwsza, gdyż w gruncie rzeczy operator ten jest tak silnie związany z klasa że powinien być jej funkcją składową.

Operator dodawania do lewej strony:

Założenia:

  1. Dodaje elementy tego samego/podobnego typu do siebie
  2. Zmienia element po lewej stronie (zwiększając go o wartość tego po prawej)
  3. Wynik powinien być zwrócony przez referencje, tak aby wskazywał na właśnie przypisany obiekt. Zwracanie wyniku przez wartość byłoby nieefektywne z względu na pamięć (zbędne kopiowanie), natomiast ważne jest zwracanie w ogóle, aby poprawna była konstrukcja while( (i+=6)<20 )

Przykład, jako funkcja składowa (do takich będę się teraz ograniczał, ew zmiany są analogiczne jak powyżej)

Listing:
  1. class Vector {
  2. ...
  3. public:
  4. Vector&       operator+=(const Vector& rhs);
  5. ...
  6. }

Operator odejmowania czyli operator- i operator -= są analogiczne, przejde więc do operatorów mnożenia. Wektory można mnożyć na 3 sposoby: wektor*liczba, liczba*wektor, wektor*liczba, oraz wektor*wektor (skalarne).

Mnożenie wektor*liczba

Założenia:

  1. Mnoży wektor po lewej stronie razy liczbę
  2. Zwraca nowy,przemnożony wektor
  3. Zwraca oczywiście przez wartość

Przykład:

Listing:
  1. class Vector {
  2. ...
  3. public:
  4.  Vector         operator*(const int& rhs)       const;
  5. ...
  6. }
Mnożenie wektor*=liczba

Założenia:

  1. Mnoży wektor po lewej stronie razy liczbę
  2. Zmienia lewą stronę wpisując wynik
  3. Zwraca referencje do przemnożonego wektora (z tych samych przyczyn co operator+=)

Przykład:

Listing:
  1. class Vector {
  2. ...
  3. public:
  4.  Vector&        operator*=(const int& rhs);
  5. ...
  6. }

Nie miałoby natomiast sensu napisanie: liczba*=wektor, gdyż takie działanie, teoretycnzie powinno liczbe zmienic na wektor, co jest niemożliwe. Pozostaje nam operator liczba*wektor. Ponieważ operator jako skladowa swoja klase musi mieć po lewej stronie, jedynym wyjściem jest utworzenie funkcji globalnej, spełniającej praktycznie te same założenia co wektor*liczba.

Listing:
  1. Vector operator* (const int& lhs,const Vector& rhs);

Często aby moc korzystać z zmiennych prywatnych klasy Vector, takie funkcje nie deklaruje się poza ich ciałem, tylko wewnątrz definicji klasy jako funkcje zaprzyjaźnione:

Listing:
  1. class Vector {
  2. ...
  3. friend Vector operator* (const int& lhs,const Vector& rhs);
  4. ...
  5. public:
  6. ...
  7. }

Ostatni operator wart wymienia to proste mnożenie skalarne wektorów, którego przykład poniżej:

Listing:
  1. class Vector {
  2. ...
  3. public:
  4.  int            operator*(const Vector& rhs)    const;
  5. ...
  6. }

Często dużo więcej można odczytać i zrozumieć z przykładowego kodu, dlatego poniżej zamieszczam w miarę dopieszczona klasę Vector :)

Udokumentowane źródła klasy Vector

]]>
http://kwesoly.net/programowanie/cpp/przeladowanie-operatorow-1/feed/ 0