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

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

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

C++ - szablony. C++ - szablony. C++ - szablony. C++ - szablony. C++ - szablony. C++ - szablony

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

Szablony. Szablony funkcji

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

Szablony klas, zastosowanie szablonów w programach

Szablony funkcji i klas (templates)

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

C++ - szablony. C++ - szablony. C++ - szablony. C++ - szablony SZABLONY SZABLONY FUNKCJI

PARADYGMATY PROGRAMOWANIA Wykład 4

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

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

Szablony funkcji i szablony klas

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

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

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

TEMAT : KLASY DZIEDZICZENIE

Obsługa wyjątków. Język C++ WW12

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

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

Zaawansowane programowanie w języku C++ Funkcje uogólnione - wzorce

Funkcje wirtualne. Wskaźniki do klas pochodnych są podstawą dla funkcji wirtualnych i polimorfizmu dynamicznego.

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

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

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

C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie C++ - DZIEDZICZENIE.

EGZAMIN 2 (14 WRZEŚNIA 2015) JĘZYK C++

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

EGZAMIN PROGRAMOWANIE II (10 czerwca 2010) pytania i odpowiedzi

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

Abstrakcyjny typ danych

Programowanie w języku C++

Zaawansowane programowanie w C++ (PCP)

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

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

Zaawansowane programowanie w języku C++ Programowanie obiektowe

Programowanie, część I

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Przeciążenie operatorów

Wykład 8: klasy cz. 4

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

Wprowadzenie do szablonów szablony funkcji

Wstęp do programowania

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

Wprowadzenie do szablonów szablony funkcji

Programowanie obiektowe w C++ Wykład 12

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

Katedra Elektrotechniki Teoretycznej i Informatyki. wykład 12 - sem.iii. M. Czyżak

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

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

PARADYGMATY PROGRAMOWANIA Wykład 3

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

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

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 15 kwietnia K.Grzelak (Wykład 8) Programowanie w C++ 1 / 33

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

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

Podział programu na moduły

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

Język C++ zajęcia nr 2

Wykład 5: Klasy cz. 3

Programowanie komputerowe. Zajęcia 7

Podstawy programowania skrót z wykładów:

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

FUNKCJE WZORCOWE. Wykład 10. Programowanie Obiektowe (język C++) Funkcje wzorcowe wprowadzenie (2) Funkcje wzorcowe wprowadzenie (1)

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

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

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

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

Część 4 życie programu

Wskaźniki. Informatyka

Laboratorium nr 10. Temat: Funkcje cz.2.

Projektowanie klas c.d. Projektowanie klas przykład

Laboratorium nr 12. Temat: Struktury, klasy. Zakres laboratorium:

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Functionalization. Funkcje w C. Marcin Makowski. 30 listopada Zak lad Chemii Teoretycznej UJ

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

Wstęp do Programowania, laboratorium 02

Funkcje. Spotkanie 5. Tworzenie i używanie funkcji. Przekazywanie argumentów do funkcji. Domyślne wartości argumentów

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

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

Identyfikacje typu na etapie. wykonania (RTTI)

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

Wykład 5 Okna MDI i SDI, dziedziczenie

Instrukcja do pracowni specjalistycznej z przedmiotu. Obiektowe programowanie aplikacji

Dziedziczenie jednobazowe, poliformizm

Wykład I. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

Wykład VII. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Język C zajęcia nr 11. Funkcje

Paradygmaty programowania. Paradygmaty programowania

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

Programowanie w C++ - wybrane przykłady szablonów Opracowanie: dr hab. Mirosław R. Dudek, prof. UZ

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

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

Programowanie, część I

1 Podstawy c++ w pigułce.

Rozdział 4 KLASY, OBIEKTY, METODY

referencje Wykład 2. Programowanie (język C++) Referencje (1) int Num = 50; zdefiniowano zmienną Num (typu int) nadając jej wartość początkową 50.

Transkrypt:

Przeciążanie a dziedziczenie class Integer2: public Integer Operatory, z wyjątkiem operatora przypisania są automatycznie dziedziczone w klasach pochodnych. Integer2(int i): Integer(i) Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) Ponieważ programiści oczekują, że operacja przypisania dla dwóch zmiennych class Integer Integer::operator=(prawy); jednakowego typu zawsze powinna się powieść, dlatego kompilator zawsze automatycznie tworzy ten operator, jeżeli programista go nie Integer(int ii): i(ii) Integer2& operator=(int ri) zdefiniuje. Integer& operator+=(const Integer& rv) Integer::operator=(ri); Działanie tego operatora jest identyczne jak domyślnego konstruktora i += rv.i; kopiującego: jeżeli klasa zawiera składowe obiekty, to dla każdego z nich wywoływany Integer& operator=(const Integer &rv) jest rekurencyjnie operator = (tzw. przypisanie za pośrednictwem i = rv.i; elementów składowych). Integer2 I2(1), J2(0); Integer K1(9); Nie należy na to pozwalać kompilatorowi, ale samemu pisać operator Integer& operator=(int ri) J2 = 5; // metoda własna przypisania, jeżeli planuje się go używać zdanie się na automatycznie i = ri; I2 = K1; // metoda własna wygenerowane operatory łatwo prowadzi do błędów. J2 = I2; //? żaden z istniejących.. I2 += J2; // metoda dziedziczona 246 247 Automatyczna konwersja typów 2 sposoby: 1. może być realizowana za pomocą konstruktora, pobierającego jako jedyny argument obiekt lub referencje do obiektu innego typu, lub 2. może być realizowana przez napisanie specjalnych przeciążonych operatorów class Jeden Jeden() class Dwa Dwa(const Jeden&) // sposób 1: // specjalny konstruktor void f(dwa) Jeden J; f(j); // kompilator to akceptuje, bo w Dwa zadeklarowano // konstruktor, którego argumentem jest obiekt typu Jeden 248 249 Może się zdarzyć, że nie chcemy, aby konstruktor był wywoływany automatycznie, jeżeli zajdą takie okoliczności, w których mógłby być tak wywołany Aby zablokować automat, używamy słowa explicit class Jeden Jeden() class Dwa explicit Dwa(const Jeden&) void f(dwa) Jeden J; // f(j)- ta instrukcja nie zadziała, bo zablokowano automatyczną konwersję f(dwa(j)); 250 251 1

Sposób 2: Automatyczna konwersja typów za pomocą operatora konwersji Można utworzyć metodę składową, pobierającą aktualny typ i przekształcającą go na typ docelowy, wykorzystując słowo kluczowe operator W takiej składowej słowo operator poprzedza nazwę typu do którego ma zostać dokonana konwersja, zamiast symbolu operatora class Trzy Trzy(int ii): i(ii) class Cztery int x; Cztery(int xx): x(xx) operator Trzy() const return Trzy(x); void g(trzy) int main(int argc, char *argv[]) Cztery cz(1); g(cz); // wywołanie operatora g(1); // wywołanie Trzy(1.0) 252 253 Automatyczna konwersja typów podsumowanie: 1. może być realizowana za pomocą konstruktora, pobierającego jako jedyny argument obiekt lub referencje do obiektu innego typu. Utworzenie jednoargumentowego konstruktora zawsze definiuje automatyczną konwersję typów nawet jeżeli argumentów jest więcej, ale pozostałe posiadają wartości domyślne. Jeżeli chcemy tego uniknąć, deklarujemy ten konstruktor jako explicit. To klasa docelowa musi mieć odpowiedni konstruktor: Dwa::Dwa(const Jeden&) void f(dwa) 2. może być realizowana przez napisanie specjalnych przeciążonych operatorów To klasa źródłowa musi mieć odpowiedni operator konwersji: Cztery::operator Trzy() const return Trzy(x); void g(trzy) 254 Automatyczna konwersja typów podsumowanie: konstruktor operator KlasaA KlasaA::KlasaA(const KlasaB&k) KlasaA::operator KlasaB() KlasaB KlasaB::KlasaB(const KlasaA&k) KlasaB::operator KlasaA() Poprawne zestawy do konwersji KlasaA KlasaB: Niepoprawne zestawy (zdublowana konwersja tylko w jedną stronę): 255 Automatyczna konwersja typów podsumowanie: Należy unikać deklarowania dwóch sposobów konwersji jednocześnie. Jeżeli: klasa X posiada możliwość przekształcenia obiektu w obiekt klasy Y za pomocą operatora Y(), a jednocześnie: klasa Y posiada konstruktor, pobierający pojedynczy argument typu X to: obydwa mechanizmy reprezentują tę samą konwersje typów i w razie potrzeby kompilator nie wie, której użyć wtedy zgłasza błąd dwuznaczności. Przewaga globalnych przeciążonych operatorów nad operatorami będącymi składowymi klas podsumowanie: w przypadku operatorów globalnych konwersja typów może zostać zastosowana do każdego z argumentów w przypadku składowej argument po lewej stronie operatora musi być odpowiedniego typu 256 257 2

class Integer Integer(int ii): i(ii) const Integer operator+(const Integer& rv) return Integer(i+rv.i); friend const Integer operator/(const Integer &arg_lewy, const Integer &arg_prawy); const Integer operator/(const Integer &arg_lewy, const Integer &arg_prawy) if (arg_prawy.i == 0) return Integer(INT_MAX); else return Integer(arg_lewy.i/arg_prawy.i); Integer I(1), J(2), K(3); I = J + 5; //I = 5 + J; // to się nie uda I = K/2; I = 10/K; // tak jest OK 258 259 SZABLONY Szablony, nazywane też wzorcami, pozwalają na abstrakcyjne definiowanie funkcji i klas w terminach parametrów, którymi są typy danych Na podstawie szablonu kompilator sam może wygenerować wiele definicji konkretnych funkcji i klas, kiedy będą potrzebne Standardowa biblioteka C++ bazuje na szablonach i dlatego jest nazywana STL: Standard Template Library 261 część 1: SZABLONY FUNKCJI Szablony funkcji Zdarza się, że wiele funkcji jest do siebie bardzo podobnych w działaniu różnią się tylko typem argumentu, który przyjmują Np. funkcja która z tablicy wybiera element o najmniejszej wartości: algorytm szukania jest wspólny dla większości typów danych. Jednak jeżeli chcemy znajdować najmniejszą wartość dla tablic z elementami typu: int, double, lub Integer (zdefiniowana klasa, dla której istnieje przeciążony operator porównania), to dla każdego z typów należy napisać na nowo całą funkcję Jeżeli te funkcje będą fragmentem biblioteki, to za każdym razem kiedy będziemy potrzebowali dopisać funkcję dla nowego typu danych w tablicy, będzie trzeba rekompilować bibliotekę i udostępniać jej użytkownikom nowy release To jest uciążliwe. Lepiej zrobić tę funkcję raz wykorzystując szablony. 263 3

Kompilator tworzy tyle wersji funkcji wg wskazanego szablonu, ile programista zażąda w swoim programie: będą takie same co do działania, ale będą różniły się co do typów argumentów wywołania, typów zmiennych lokalnych czy typu wartości zwracanej Szablony można tworzyć nawet dla typów, które w chwili pisania szablonu jeszcze w ogóle nie istniały Aby poinformować kompilator, że kod, który piszemy reprezentuje szablon, należy użyć słowa kluczowego template - kod, który znajduje się poniżej tego słowa jest definicją wzorca funkcji lub klasy Przykład: template <class T1, class T2> T2& moja_funkcja(t1 arg1, T2* arg2) // Tutaj jakiś kod funkcji // wykorzystującej typy T1 i T2 return *arg2; W nawiasach kątowych lista parametrów formalnych wzorca, każdy poprzedzony słowem class, lub typename (typename wprowadzono później) Parametry zwyczajowo nazywa się z wykorzystaniem T, np. T1, T2 Następnie występuje definicja wzorca wykorzystująca T1 i T2 tam, gdzie powinna występować nazwa konkretnego typu 264 265 Na podstawie typów argumentów kompilator ma zgadnąć, który szablon i jak należy wykorzystać: template <class T1, class T2> T2& moja_funkcja(t1 arg1, T2* arg2) return *arg2; int a = 9; double b = 10.2, c = 3.14; moja_funkcja(a, &b); // konkretyzacja wzorca na // double& moja_funkcja(int arg1, double* arg2) moja_funkcja(a, &c); // tu nie ma konkretyzacji funkcja już jest. moja_funkcja(b, &a); // konkretyzacja wzorca na //int& moja_funkcja(double arg1, int* arg2) Słowo kluczowe class w linii: template <class T1, class T2> nie oznacza, że T1 i T2 mogą być tylko klasami (jak widać na przykładzie); mogą to być dowolne typy (wbudowane lub definiowane przez użytkownika) Dla czytelności w późniejszych wersjach kompilatorów zastąpiono to słowo słowem typename template < typename T1, typename T2> 266 267 Przeciążanie szablonów funkcji: template <typename T> T wiekszy(const T& k1, const T& k2) return k1 < k2? k2 : k1 ; double wiekszy(const double& d1, const double& d2) return d1 < d2? d2 : d1 ; int a, b=0, c=1; a = wiekszy(b,c); // która wersja funkcji zostanie użyta? // Istnieje standardowa konwersja int na double, ale // istnieje też szablon wg którego można utworzyć // właściwą funkcję double x, y=0.3, z=2.14; x = wiekszy(y,z); // która wersja funkcji zostanie użyta? Wskazywanie wartości parametru szablonu class Integer Integer(int ii): i(ii) bool operator<( const Integer& rv) const return i < rv.i; bool operator>( const Integer& rv) const return i > rv.i; template <typename T> T wiekszy(const T& k1, const T& k2) return k1 < k2? k2 : k1 ; Integer I1(0), I2(1), I3(2); I1 = wiekszy<integer>(i2, I3); Jeżeli nie ma jednoznacznej interpretacji, można za nazwą szablonu w nawiasach kątowych podać listę typów, które należy w tym miejscu zastosować 268 269 4

Informacja o typie zmiennej Testując szablony czasem niezbędne jest sprawdzenie, jakiego typu są zmienne, których szablon używa (czy np. kompilator sam podjął decyzję o konwersji zmiennej na podobny typ, etc) Do sprawdzenia służy operator typeid Operator zwraca obiekt typu const std::type_info Klasa ta ma pożyteczną metodę name() Chciałoby się napisać: std::type_info typ = typeid(a); printf("%s\n",typ.name()); Jednak autorzy biblioteki sprytnie zastrzegli konstruktor kopiujący oraz operator przypisania jako private uniemożliwiając de facto tworzenie w programie własnych obiektów tego typu z obiektów zwracanych przez operator typeid: private: /// Assigning type_info is not supported. Made private. type_info& operator=(const type_info&); type_info(const type_info&); Dlatego aby wywołać metodę name można wyłącznie napisać tak: printf("%s\n",typeid(k1).name()); 270 271 Porada programistyczna Na etapie testowania programu można w szablonie funkcji i w funkcji dodać instrukcje ujawniające typ danych, które są przetwarzane: template <typename T> T wiekszy(const T& k1, const T& k2) printf("szablon dla: %s\n",typeid(k1).name()); return k1 < k2? k2 : k1 ; double wiekszy(const double& d1, const double& d2) printf("dla double: %s\n",typeid(d1).name()); return d1 < d2? d2 : d1 ; część 2: SZABLONY KLAS 272 Szablony klas Na tej samej zasadzie co szablony funkcji można tworzyć szablony klas Składnia jest analogiczna: template <typename T, typename M> class Klasa // tu używamy typów T i M Aby utworzyć obiekt nie możemy napisać: Klasa K; bo nie wiadomo, jakie typy przypisać parametrom M i T, a kompilator nie ma szansy domyślić się. Wskazanie wartości parametrów jest konieczne. Szablony klas Deklaracja obiektów: template <typename T, typename M> class Klasa // tu używamy typów T i M Klasa<double, int> K; Klasa<int, Integer> I; 274 275 5

Szablony klas Jeżeli chcemy, żeby metody tej klasy zostały definiowane poza szablonem klasy, to musimy tam prawidłowo napisać nazwę szablonu: Klasa::Klasa(); // konstruktor domyślny Źle! template <typename T, typename M> Klasa<T, M>::Klasa(); // kontruktor domyślny Dobrze! Parametry szablonu klasy mogą być też wartościami określonego typu, np. : template <typename T, int rozmiar > class Klasa // tu używamy typu T i zmiennej rozmiar Klasa<int, 100> Tab; Klasa<double, 2000> *Tab2; Klasa<double, 3000> *Tab3; Tab, Tab2 i Tab3 są obiektami różnych typów, dlatego kompilator nie zaakceptuje takich instrukcji jak przepisanie wartości między wskaźnikami, itp. 276 277 Projekt składający się z pliku main.cpp i biblioteki (para plików:.cpp i.h) wyklad13b.h template <typename T, int rozmiar> class Tablica wyklad13b.cpp #include wyklad13b.h" Kompilacja szablonów Zawsze kiedy ukonkretniany jest szablon klasy, kod definicji takiej klasy dla danej specjalizacji jest generowany wraz z metodami składowymi wywoływanymi w programie i tylko z tymi rzeczywiście wywoływanymi metodami składowymi. Jest to unikanie nadmiarowego kodu. To daje możliwość elastycznego projektowania szablonów, wykorzystującego różne właściwości różnych konkretnych typów. main.cpp #include wyklad13b.h" Tablica<int, 100> Tab1; 278 279 class Pierwsza void f() class Druga void g() template<typename T> class Trzecia T t; void a() t.f(); void b() t.g(); int main() Trzecia<Pierwsza> TP; TP.a(); // nie tworzy Trzecia<Pierwsza>::b() Trzecia<Druga> TD; TD.b(); // nie tworzy Trzecia<Druga>::a() Szablony vs. pliki nagłówkowe Zasada: deklaracje i kompletne definicje szablonów funkcji i klas umieszczamy w pliku nagłówkowym (i tylko tam). Uzasadnienie: Skoro szablony są wykorzystywane do generowania kodu tylko gdy w kodzie wystąpi wykorzystanie szablonu, to: 1. Umieszczenie kodu metod i funkcji w pliku cpp sprawi, że będzie on kompilowany oddzielnie nie będzie w tym pliku instrukcji wykorzystujących szablon, które należą do innych funkcji i metod, a więc kompilator nie będzie wiedział jakich konkretyzacji dokonać 2. Tam, gdzie będą próby wykorzystania szablonu, kompilator będzie miał same nagłówki klas i funkcji, ale bez definicji, więc nie będzie potrafił skonkretyzować żądanych wersji szablonu Efekt uboczny: kod szablonów jest jawny dla każdego użytkownika naszej biblioteki (pliki nagłówkowe są dostarczane zawsze w postaci źródłowej) 280 281 6