C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Podobne dokumenty
C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy WSKAŹNIKI KLASOWE

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) { zdefiniuje. Integer::operator=(ri);

C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm POLIMORFIZM

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

Przeciążanie operatorów

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Programowanie obiektowe Wykład 3. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21

Języki i techniki programowania Ćwiczenia 2

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Podstawy programowania. 1. Operacje arytmetyczne Operacja arytmetyczna jest opisywana za pomocą znaku operacji i jednego lub dwóch wyrażeń.

TEMAT : KLASY DZIEDZICZENIE

Języki programowania C i C++ Wykład: Typy zmiennych c.d. Operatory Funkcje. dr Artur Bartoszewski - Języki C i C++, sem.

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 28 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27

Tablice mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Zaawansowane programowanie w języku C++ Przeciążanie operatorów

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 13 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 30

Szablony klas, zastosowanie szablonów w programach

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Przeciążenie operatorów

PARADYGMATY PROGRAMOWANIA Wykład 3

Laboratorium nr 10. Temat: Funkcje cz.2.

Wstęp do wskaźników w języku ANSI C

Język C++ zajęcia nr 2

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Wykład 5: Klasy cz. 3

C++ Przeładowanie operatorów i wzorce w klasach

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Programowanie, część I

Lab 9 Podstawy Programowania

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy KONSTRUKTORY

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

Wykład 8: klasy cz. 4

ROZDZIAŁ 2. Operatory

Wykład 4: Klasy i Metody

Programowanie obiektowe. Materiały przygotował: mgr inż. Wojciech Frohmberg

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 4. Karol Tarnowski A-1 p.

Programowanie Obiektowe i C++

Dr inż. Grażyna KRUPIŃSKA. D-10 pokój 227 WYKŁAD 7 WSTĘP DO INFORMATYKI

W dowolnym momencie można zmienić typ wskaźnika.

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy PRAWA PRZYJACIÓŁ KLASY. Dostęp z zewnątrz: Dostęp z wewnątrz:

Zmienne, stałe i operatory

Języki i paradygmaty programowania

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Funkcje przeciążone, konstruktory kopiujące, argumenty domyślne

Wskaźniki. Informatyka

wykład II uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - funkcje, tablice i wskaźniki wykład II dr Jarosław Mederski Spis

Język C++ umożliwia przeciążanie operatora, tzn. zmianę jego znaczenia na potrzeby danej klasy. W tym celu definiujemy funkcję o nazwie:

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

Część 4 życie programu

Programowanie w języku C++

Techniki Programowania wskaźniki

> C++ wskaźniki. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki 26 kwietnia 2017

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Różne właściwości. Różne właściwości. Różne właściwości. C++ - klasy. C++ - klasy C++ - KLASY

Programowanie obiektowe i C++ dla matematyków

Podstawy programowania w języku C i C++

Wyliczanie wyrażenia obiekty tymczasowe

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Programowanie obiektowe, wykład nr 7. Przegląd typów strukturalnych - klasy i obiekty - c.d.

Odczyt danych z klawiatury Operatory w Javie

C++ - szablony kontenerów. Kontenery i szablony kontenerów. C++ - szablony kontenerów. C++ - szablony kontenerów. C++ - szablony kontenerów

MATERIAŁY DO ZAJĘĆ II

Programowanie obiektowe i C++ dla matematyków

Aplikacje w środowisku Java

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Operacje wykonywane są na operandach (argumentach operatorów). Przy operacji dodawania: argumentami operatora dodawania + są dwa operandy 2 i 5.

Wstęp do programowania

Wykład 2 Składnia języka C# (cz. 1)

ZASADY PROGRAMOWANIA KOMPUTERÓW

Podstawy Programowania Obiektowego

Wstęp do programowania obiektowego. Wykład 2

1 Podstawy c++ w pigułce.

Wykład 3 Składnia języka C# (cz. 2)

IX. Wskaźniki.(3 godz.)

PARADYGMATY PROGRAMOWANIA Wykład 4

Materiały do zajęć VII

Programowanie w języku C++

Programowanie w C++ Wykład 13. Katarzyna Grzelak. 4 czerwca K.Grzelak (Wykład 13) Programowanie w C++ 1 / 26

Konwersje napis <-> liczba Struktury, unie Scanf / printf Wskaźniki

Operator przypisania. Jest czym innym niż konstruktor kopiujący!

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

Instrukcje warunkowe i skoku. Spotkanie 2. Wyrażenia i operatory logiczne. Instrukcje warunkowe: if else, switch.

Ok. Rozbijmy to na czynniki pierwsze, pomijając fragmenty, które już znamy:

Szablony funkcji i szablony klas

Programowanie obiektowe - Przykładowe zadania egzaminacyjne (2005/2006)

Transkrypt:

Operatory są elementami języka C++. Istnieje zasada, że z elementami języka, takimi jak np. słowa kluczowe, nie można dokonywać żadnych zmian, przeciążeń, itp. PRZECIĄŻANIE OPERATORÓW Ale dla operatorów zrobiono wyjątek: operatory można przeciążać. 217 Co to znaczy przeciążyć operator? Przeciążanie operatorów polega na napisaniu nowych funkcji lub metod, które wywołujemy w taki sam sposób jak operatory. Nie da się modyfikować sposobu działania już zdefiniowanych przypadków użycia danego operatora, ale można wprowadza nowe, których do tej pory nie było i których obecność ułatwi pisanie kodu. Nie przeciąża się operatora dodawania dwóch liczb typu double. Można natomiast przeciążyć operator dodawania tak aby można było pisać wyrażenia arytmetyczne, których argumentami są obiekty zdefiniowanego przez nas typu. Dlatego.. jedynie wyrażenia obejmujące typy zdefiniowane przez użytkownika mogą zawierać przeciążone operatory. 218 219 Definiując funkcję reprezentującą przeciążony operator, jako jej nazwę piszemy: operator@, gdzie znak @ reprezentuje przeciążony operator (np. +, -, /, *..) Istnieją cztery możliwości: 1. Operator przeciążony może być zdefiniowany jako 1. funkcja globalna, albo 2. metoda należąca do klasy. 2. Operator przeciążony może być 1. jedno-, albo 2. dwuargumentowy. Jeżeli przeciążamy operator, który ma działać jako funkcja globalna, to po słowie operator@ zapisujemy 1. dwa argumenty jeżeli jest to operator dwuargumentowy, lub 2. jeden jeżeli jednoargumentowy Jeżeli przeciążamy operator, który ma działać jako metoda należąca do klasy, to po słowie operator@ mamy 1. brak argumentów, jeżeli operator jest jednoargumentowy, lub 2. jeden argument jeżeli dwuargumentowy. W tym przypadku obiekt, na rzecz którego będzie wywoływany przeciążony operator staje się argumentem lewostronnym 220 221 1

Zdefiniujmy klasę, która ma reprezentować liczbę typu całkowitego (integer). Chcielibyśmy, aby na obiektach tej klasy można było dokonywać operacji arytmetycznych w taki sam sposób, jak na zmiennych typu int. Klasa będzie nazywała się Integer Na początek będziemy dla niej potrzebowali: 1. konstruktora pozwalającego na ustalenie przechowywanej wartości oraz 2. operator dwuargumentowy: +=, przy czym argumentami operatora mają być obiekty typu Integer Integer(int ii): i(ii) Integer& operator+=(const Integer& rv) int get_i() return i; 222 223 Ponieważ operator jest dwuargumentowy, definiujemy jeden argument wywołania Przekazujemy argument przez referencje aby niepotrzebnie nie wymuszać tworzenia kopii Deklarujemy argument jako const aby zagwarantować mu nietykalność Ponieważ operator nie zwraca żadnej wartości, moglibyśmy napisać: void operator+=(const Integer& rv) ale.. Integer(int ii): i(ii) Integer& operator+=(const Integer& rv) int get_i() return i;..w C++ przyjmujemy że wszystkie operacje przypisania oprócz czynności przekopiowania wartości dodatkowo zwracają je jako rezultat swego działania. To umożliwia tworzenie wyrażeń kaskadowych: A+=B+=C+=D; Aby zachować tę właściwość deklarujemy, że operator zwraca referencję do obiektu typu Integer Integer(int ii): i(ii) Integer& operator+=(const Integer& rv) int get_i() return i; 224 225 Operator dodawania Działając na typach wbudowanych, dodawanie polega na utworzeniu zmiennej pomocniczej i zapisaniu do niej wyniku sumowania wartości z lewego i prawego argumentu wyrażenia: int a, b=1, c=2; a = b + c; Operator dodawania const Integer operator+(const Integer& rv) Metoda tworzy zmienną lokalną takiego samego typu, której zadaniem będzie przechować wynik dodawania. Metoda zwraca tę zmienną, która jest następnie kopiowana np. do zmiennej po lewej stronie równości: a = b + c; Po kopiowaniu zmienna lokalna jest usuwana. 226 227 2

const Integer operator+(const Integer& rv) Integer(int ii): i(ii) printf("%i\n",i); Integer& operator+=(const Integer& rv) const Integer operator+(const Integer& rv) int get_i() return i; Integer I(1), J(2), K(3); I += J + K; printf("%i\n",i.get_i()); // co pojawi się w oknie konsoli? Zmienna lokalna zwracana przez metodę jest obiektem tymczasowym: ma za zadanie tylko zwrócić wartość i zniknąć. Nie zwracamy jej przez podanie jej adresu (to byłoby niebezpieczne!), tylko przez wartość Ponadto deklarujemy ją jako const. Ma to chronić przed takimi wybrykami, jak np. wywołanie metody należącej do obiektu zwracanego przez wyrażenie, np. : (a+b).fun() Dzięki uczynieniu wartości zwracanej jako const określa się, że dla tej wartości mogą być wywołane jedynie stałe składowe (również metody) klasy Integer. To zapobiega umieszczeniu w obiekcie nowej, potencjalnie wartościowej informacji 228 229 Czego nie wolno robić? Nie można tworzyć operatorów, które nie posiadają znaczenia w języku C, np. poprzez łączenie już istniejących (nowy operator ** utworzony w ten sposób mógłby oznaczać potęgowanie, ale niestety..) Nie wolno zmieniać kolejności obliczania operatorów Nie wolno zmieniać liczby argumentów Operatory jednoargumentowe minus i negacja: const Integer operator-() return Integer(-i); const Integer operator!() return Integer(!i); Integer I(1), J(2), K(3); I = -J; printf("%i\n",i.get_i()); I =!K; printf("%i\n",i.get_i()); 230 231 Inkrementacja i dekrementacja Jak rozróżnić wywołanie przyrostkowe i przedrostkowe (operator w obydwu przypadkach wygląda tak samo)? Okazuje się, że kompilator już sobie z tym poradził pierwszy w związku z typami wbudowanymi: 1. jeżeli kompilator widzi ++a, generuje wywołanie funkcji operator++(a) 2. jeżeli kompilator widzi a++, generuje wywołanie funkcji operator++(a,int) Kompilator rozróżnia te dwie postacie wywołując dwie funkcje mające różne sygnatury. Kompilator sam przekazuje sztuczną, stałą wartość argumentu typu int const Integer& operator++() i++; const Integer operator++(int) Integer wart_przed(i); i++; return wart_przed; friend const Integer& operator--(integer &a); friend const Integer operator--(integer &a, int); const Integer& operator--(integer &a) a.i--; return a; const Integer operator--(integer &a, int) Integer wart_przed(a.i); a.i--; return wart_przed; 232 233 3

const Integer operator*( Integer &a) return Integer(i *a.i); friend const Integer operator/(integer &arg_lewy, Integer &arg_prawy); const Integer operator/(integer &arg_lewy, Integer &arg_prawy) if (arg_prawy.i == 0) return Integer(INT_MAX); else return Integer(arg_lewy.i/arg_prawy.i); Argumenty: 1. jeżeli zamierzamy tylko odczytywać zwracaną wartość, argument powinien zostać przekazany jako referencja do stałej (const). 2. Jedynie w przypadku operatorów zmieniających argument po lewej stronie (połączonych z przypisaniem, jak np. += oraz operator= ) argument po lewej stronie nie może być stałą Zwracane wartości: 1. Typ wartości zwracanej przez operator powinien zależeć od spodziewanego znaczenia operatora 2. Wartości zwracane przez operatory przypisania powinny być referencjami do l-wartości, niebędącymi referencjami do stałych 3. Wynikiem działania operatorów logicznych są przynajmniej liczby całkowite a najlepiej wartości typu bool. Nie należy tego zmieniać 234 235 W przeciążonym operatorze mnożenia można napisać tak: const Integer operator*(integer &a) return Integer(i *a.i); albo tak: const Integer operator*(integer &a) Integer tmp(i * a.i); return tmp; W przeciążonym operatorze mnożenia można napisać tak: return Integer(i * a.i); albo tak: Integer tmp(i * a.i); return tmp; Przypadek pierwszy: utwórz tymczasowy obiekt w miejscu przeznaczonym na wartość zwracaną przez funkcję jedna operacja Przypadek drugi: Czy jest różnica w działaniu? utwórz lokalny obiekt tmp, wywołaj konstruktor kopiujący, żeby skopiować tmp do miejsca znajdującego się na zewnątrz funkcji, przeznaczonego na zwracaną przez nią wartość. wywołaj destruktor tmp usuwając ten obiekt trzy operacje 236 237 Przeciążanie operacji przypisania Gdy używany jest znak = to czasem następuje przypisanie, a czasem wywoływany jest konstruktor kopiujący, np. : 1. Integer a(1); 2. Integer b = a; 3. b = a; W drugiej linijce tworzony jest nowy obiekt oraz inicjalizowany wartością a. Przy tworzeniu wywoływany jest zawsze konstruktor. Kompilator połączy to w całość i wywoła konstruktor kopiujący: b(a) W trzeciej linijce zostanie wywołana metoda Integer::operator= Z reguły przy inicjalizowaniu obiektu za pomocą =, zamiast dwóch operacji: (1) wywołania konstruktora i (2) operacji przypisania, kompilator chce wykonać jedną: poszukuje konstruktora, który przyjmie jako argument to, co znajduje się po prawej stronie operacji przypisania. Dlatego dla jasności lepiej jest unikać wykorzystywania znaku = do inicjalizacji obiektów i zamiast tego zawsze używać wywołania konstruktora 238 239 4

A jeżeli mamy zwykłe przypisanie wartości..? Jeżeli programista nie zdefiniuje operatora przypisania to kompilator dostarczy własny operator przypisania, który skopiuje obiekt pole po polu. Ten operator może generować błędy, ponieważ: nie będzie działał dla pól stałych, nie będzie działał dla referencji, dla wskaźników skopiuje wartość. Własny operator przypisania const Integer operator=(const Integer &rv) i = rv.i; Gdyby wśród składowych klasy były wskaźniki, należałoby rozstrzygnąć, czy je przepisywać, czy kopiować ich zawartość, ewentualnie jeżeli rozmiary struktur nie byłyby zgodne usunąć poprzednie i założyć nowe o nowym rozmiarze. 240 241 Przeciążanie operatorów [] klasa reprezentująca typ tablicowy. Obiekt ma reprezentować tablicę, do której można się odwoływać intuicyjnie, np. Tab[i] Ma być też dostępnych kilka innych metod ułatwiających operacje na tej tablicy, np. rozmiar(). class Tablica int rozm; int *wsk; Tablica( int = 10 ); Tablica( const Tablica& ); ~Tablica(); int rozmiar(void) const return rozm; const Tablica &operator=( const Tablica& ); bool operator==( const Tablica& ); int &operator[]( int ); const int &operator[]( int ) const; 242 243 ; Implementacja przeciążonego operatora []: int &Tablica::operator[]( int i) assert (0 <= i && i < rozm); return wsk[i]; } // operator dla obiektów zadeklarowanych jako const const int &Tablica::operator[]( int i) const assert (0 <= i && i < rozm); return wsk[i]; } Przykład wykorzystania: Tablica Tab1(5), Tab2; for (int i=0; i<tab1.rozmiar(); i++) Tab1[i] = i; Tab2 = Tab1; assert(tab2 == Tab1); 244 245 5