[Kurs C++] Przeciążanie operatorów
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
var pageTracker = _gat._getTracker("UA-3650348-1");
pageTracker._initData();
pageTracker._trackPageview();
Serwis został przeniesiony pod nową domenę: http://cpp0x.pl/ Strona główna Kursy Artykuły Forum Pliki Promuj Nas! PowrótHistoria odwiedzonych stronPoprzednia lekcjaKurs C++Następna lekcjaAutor: Michał śPętlik” PętlickiPrzeciążanie operatorów?.1. O co chodzi z tymi operatorami??W języku C++ dostępne są różne typy zmiennych przechowujących wartości liczbowe (np. int, double). Jednak byłoby trochę bezsensowne, gdyby nie można było z tymi danymi nic zrobić. Właśnie, dlatego powstały operatory umożliwiające operacje na zmiennych np.int x, y;x=2;y=3;int z= x+y;Jednak, gdy tworzymy własną klasę posiadającą wiele wartości, to w chwili, gdy będziemy próbowali je dodać w sposób, jak powyżej kompilator zgłupieje i nie będzie wiedział, co zrobić. Można oczywiście zrobić metodęvoid MojaKlasa::dodaj(MojaKlasa x);Rozwiąże ona nasz problem, jednak użycie jej jest mocno niewygodne. Ponadto, gdy trzeba będzie użyć kilku działań to kod zacznie wyglądać strasznie nieczytelnie, a szukanie jakichkolwiek błędów będzie koszmarem. Na szczęście w C++ istnieje możliwość przeciążenia operatorów takich jak Ś+’, Ś-Ś, Ś+=’, Ś==’ i innych, tak żeby działał bezpośrednio z naszą klasą.?.2. Operatory w klasieNa potrzeby tego artykułu utwórzmy klasę ŚVector’, która jak sama nazwa wskazuje będzie reprezentować wektor na płaszczyźnie kartezjańskiej. Załączymy do niej od razu konstruktory.class Vector{ public: double x; double y; Vector() { this->x= 0; this->y= 0; } Vector(double x, double y) { this->x= x; this->y= y; }}Ogólna zasada pisania operatorów w klasie wygląda następująco:zwracany_typ operator@(typ_prawego_operandu &nazwa_prawego_operandu);gdzie Ś@’ to operator, który chcemy przeciążyć. Pierwszym argumentem przy przeciążaniu w klasie zawsze jest zmienna Śthis’, która jest przedstawicielem tej klasy. Taka mała oszczędność czasu. Drugi (opcjonalny) parametr jest przekazywany jako wskaźnik w argumencie funkcji.Pierwszym operatorem, jaki przeciążymy będzie negacja(Ś!’), która zwróci wektor przeciwny. Dopiszmy do ciała naszej klasy:Vector operator!(){ return Vector(-this->x, -this->y);}Zgodnie ze schematem – pierwszym argumentem jest ŚVector this’, drugiego argumentu nie ma, więc funkcja nie ma parametrów, a zwracany jest nowa zmienna ŚVector’.Kolejną rzeczą, jaką zrobimy jest porównywanie (Ś==’). Osoby, które programują w C/C++ wiedzą, że zwraca on wartość logiczną Śtrue’, jeśli operandy są takie same lub Śfalse’ w innym przypadku. Aby zadziałało to w naszej przykładowej klasie musimy dodać no niej następującą metodę:bool operator==(const Vector &v){ if( (this->x==v.x) && (this->y==v.y) ) return true; else return false;}Porównywanie, jak pewnie większość wie jest dwuanrumentowe, Zatem zgodnie z powyższym schematem – wartością zwracaną jest Śbool’, pierwszym operandem ŚVector this’, a drugim przekazany przy wywołaniu argument ŚVector &v’.Przejdźmy teraz do następnego operatora, czyli do Ś+’. Dopiszmy do klasy poniższy kod:Vector operator+(const Vector &v){ return Vector(this->x+ v.x, this->y+ v.y);}Jak w poprzednim przypadku pierwszym argumentem jest domyślnie nasza klasa, drugim podany w funkcji argument. Zwracaną wartością jest nowa zmienna, w której jak można się domyślić x i y, są sumą swoich odpowiedników z operandów. Skoro mamy zwykłe dodawanie to, może czas, żeby zrobić obsługę operatora Ś+=’. Po raz kolejny do klasy załączamy kod:Vector & operator+=(const Vector &v){ this->x+= v.x; this->y+= v.y; return *this;}Od razu widać, że to nie jest takie proste jak poprzednia wersja. Problem wynika z tego, że w tym przypadku nie jest zwracana nowa znienna, tylko modyfikowany jest pierwszy argument, a zwracany jest wskaźnik na niego. Takie rozwiązanie należy stosować zawsze, gdy pierwszy operand jest modyfikowany.W analogiczny sposób możemy zrobić przeciążenie operatora, gdy drugi operand jest czymś innym niż nasza klasaVector operator*(const double &d){ Vector ret; ret.x= this->x * d; ret.y= this->y * d; return ret;}Vector & operator*=(const double &d){ this->x*= d; this->y*= d; return *this;}?.3. Operatory poza klasąOstatni przykład pozwala nam wykonać następującą instrukcję:v= v*0.5;Gdzie zmienna Śv’ jest przedstawicielem naszej klasy. Jednak definicje operacji nie są przemienne i gdy będziemy chcieli skompilowaćv= 0.5*v;otrzymamy błąd. Niestety klasa double nie istnieje, a nawet gdyby istniała to i tak nie moglimyśmy jej edytować. Dlatego istnieje możliwość przeciążenia operatorów również poza klasą. Schemat, którego nalezy się trzymać wygląda następująco:zwracany_typ operator@(typ_lewego_operandu &nazwa_lewego_operandu, typ_lewego_operandu &nazwa_lewego_operandu)Wygląda to bardzo podobnie do przeciążania w klasie, jednak z pewną różnicą. Jest nią konieczność definiowania funkcji poza klasą, a co za tym idzie – trzeba przekazać do funkcji wskaźniki na oba operandy. Definicja funkcji która przy mnożeniu jako lewostronny operand przyjmuje Śdouble’, a dopiero jako prawostronny ŚVector’ wygląda w następujący sposób:Vector operator*(const double &d, const Vector &v){ return Vector(v.x * d, v.y * d);} Teraz żeby nie odnieść mylnego wrażenia, że operatory odpowiadają tylko za działania arytmetyczne zróbmy coś innego. Programiści javy mają do swojej dyspozycji funkcję standardową toString(), która jest wykorzystywana do automatycznego konwertowania naszej zmiennej na napis. W C++ taka funkcja nie istnieje. Jednak istnieje możliwość przeciążenia operatora Ś<<’ z lewostronnym operandem typu Śstr::ostream’ i zwracaną wartością w takim samym formacie. Da to w rezultacie taki sam efekt. Przykład takiego zastosowania wygląda następująco:std::ostream & operator<<(std::ostream& s, const Vector& v){ return s << '<' << v.x << ',' << v.y << '>';}Poniżej zamieszczona jest tabelka z możliwymi do przeciążenia operatorami i scematami jak to zrobić.opetarorschematw klasiepoza klasą+_zwracany_typ_ operator+(const _typ_&);_zwracany_typ_ operator+(const _typ1_&, const _typ2_&);-_zwracany_typ_operator-(const _typ_&);_zwracany_typ_ operator-(const _typ1_&, const _typ2_&);*_zwracany_typ_ operator*(const _typ_&);_zwracany_typ_ operator*(const _typ1_&, const _typ2_&);/_zwracany_typ_ operator/(const _typ_&);_zwracany_typ_ operator/(const _typ1_&, const _typ2_&);%_zwracany_typ_ operator%(const _typ_&);_zwracany_typ_ operator%(const _typ1_&, const _typ2_&);^_zwracany_typ_ operator^(const _typ_&);_zwracany_typ_ operator^(const _typ1_&, const _typ2_&);&_zwracany_typ_ operator&(const _typ_&);_zwracany_typ_ operator&(const _typ1_&, const _typ2_&);|_zwracany_typ_ operator|(const _typ_&);_zwracany_typ_ operator|(const _typ1_&, const _typ2_&);~_zwracany_typ_ operator~();_zwracany_typ_ operator~(const _typ_&);!_zwracany_typ_ operator!();_zwracany_typ_ operator!(const _typ_&);=_zwracany_typ_ & operator=(const _typ_&);_zwracany_typ_ & operator=(_zwracany_typ_&, const _typ_&);<_zwracany_typ_ operator<(const _typ_&);_zwracany_typ_ operator<(const _typ1_&, const _typ2_&);>_zwracany_typ_ operator>(const _typ_&);_zwracany_typ_ operator>(const _typ1_&, const _typ2_&);+=_zwracany_typ_ & operator+=(const _typ_&);_zwracany_typ_ & operator+=(_zwracany_typ_&, const _typ_&);-=_zwracany_typ_ & operator-=(const _typ_&);_zwracany_typ_ & operator-=(_zwracany_typ_&, const _typ_&);*=_zwracany_typ_ & operator*=(const _typ_&);_zwracany_typ_ & operator*=(_zwracany_typ_&, const _typ_&);/=_zwracany_typ_ & operator/=(const _typ_&);_zwracany_typ_ & operator/=(_zwracany_typ_&, const _typ_&);%=_zwracany_typ_ & operator%=(const _typ_&);_zwracany_typ_ & operator%=(_zwracany_typ_&, const _typ_&);^=_zwracany_typ_ & operator^=(const _typ_&);_zwracany_typ_ & operator^=(_zwracany_typ_&, const _typ_&);&=_zwracany_typ_ & operator&=(const _typ_&);_zwracany_typ_ & operator&=(_zwracany_typ_&, const _typ_&);*=_zwracany_typ_ & operator|=(const _typ_&);_zwracany_typ_ & operator|=(_zwracany_typ_&, const _typ_&);<<_zwracany_typ_ & operator<<(const _typ_&);_zwracany_typ_ & operator<<(const _zwracany_typ_&, const _typ_&);>>_zwracany_typ_ & operator>>(const _typ_&);_zwracany_typ_ & operator>>(const _zwracany_typ_&, const _typ_&);<<=_zwracany_typ_ & operator<<=(const _typ_&);_zwracany_typ_ & operator<<=(_zwracany_typ_&, const _typ_&);>>=_zwracany_typ_ & operator>>=(const _typ_&);_zwracany_typ_ & operator>>=(_zwracany_typ_&, const _typ_&);==_zwracany_typ_ operator==(const _typ_&);_zwracany_typ_ operator==(const _typ1_&, const _typ2_&);!=_zwracany_typ_ operator!=(const _typ_&);_zwracany_typ_ operator!=(const _typ1_&, const _typ2_&);<=_zwracany_typ_ operator<=(const _typ_&);_zwracany_typ_ operator<=(const _typ1_&, const _typ2_&);>=_zwracany_typ_ operator>=(const _typ_&);_zwracany_typ_ operator>=(const _typ1_&, const _typ2_&);&&_zwracany_typ_ operator&&(const _typ_&);_zwracany_typ_ operator&&(const _typ1_&, const _typ2_&);||_zwracany_typ_ operator||(const _typ_&);_zwracany_typ_ operator||(const _typ1_&, const _typ2_&);++_zwracany_typ_ & operator++();_zwracany_typ_ & operator!=(_typ_&);--_zwracany_typ_ & operator--();_zwracany_typ_ & operator--(_typ_&);->*_zwracany_typ_ operator->*(const _typ_&);_zwracany_typ_ operator->*(const _typ1_&, const _typ2_&);->_zwracany_typ_ operator->(const _typ_&);_zwracany_typ_ operator->(const _typ1_&, const _typ2_&);?.4. Uwagi końcoweOperatory są rozróżniane po operatorze i typach operandów. Oznacza to, że niemożliwe jest napisanie 2 operatorów różniących się tylko zwracanym typem.Operatory takie jak == != < > <= >= zazwyczaj zwracają wartość logiczną, czyli typ bool, jednak możliwe jest przeciążenie w taki sposób, żeby działały w inny spocób.Operatory + - itp zazwyczaj nie modyfikuja operandów jednak nic nie stoi na przeszkodzie, żeby napisać przeciązenie w taki sposób, żeby działały jak += -= itp. Konieczne jest wtedy usunięcie słowa kluczowego const z definicji funkcji. Operatory += -= *= itp powinny mieć zwracany typ identyczny, jak lewy operand.Poprzednia lekcjaKurs C++Następna lekcjaWszelkie prawa zastrzeżone. Autor: źródło zewnętrzneWszystkie teksty są chronione prawami autorskimi. Kopiowanie lub rozpowszechnianie treści bez wyraźnej zgody jego autora jest zabronione.PowrótHistoria odwiedzonych stronPanel LogowaniaLogin:Hasło:Zapamiętaj mnie!Zarejestruj sięOdzyskiwanie hasłaUżytkownikówObecnie aktywnych:12Zalogowanych:0Zarejestrowanych:4367Ostatnie 24h:413Non-cookie 24h:3190Wszystkich:264759Ostatnia Aktualizacja2010-11-23 00:46:20 (39 dni temu)Ostatnio aktywniHandy9020 godzPiotr Szawdyński21 godzFletcher37 godzwiew39 godzPietrzuch40 godzmat250148 godzbooncki51 godzRaver73 godzWynajem Sopot - wakacjePokój 2 osobowy 130zł/doba;Lokalizacja: Sopothttp://sopotwynajem.pl
O portaluArchiwumHistoriaIndeksRegulaminWyszukiwarkaLinkiRestauracja "ATOL" - Sopot© Wszelkie prawa zastrzeżone 2005-2011Czas wygenerowania strony: 0.080sAutor: Piotr Szawdyński
Wyszukiwarka
Podobne podstrony:
IndexEindexesindexe315indexed5cindexe339IndexedPropertyChangeEventjava beans IndexedPropertyDescriptorChapter 18 indexers csproj FileListAbsoluteIndexedPropertyDescriptorIndexedPropertyChangeEventwięcej podobnych podstron