Programowanie w C++ Wykład 12 Katarzyna Grzelak 20 maja 2019 K.Grzelak (Wykład 12) Programowanie w C++ 1 / 32
Klasy - powtórzenie Klasy typy definiowane przez użytkownika Klasy zawieraja dane składowe plus funkcje składowe (metody) K.Grzelak (Wykład 12) Programowanie w C++ 2 / 32
Konstruktory i destruktory - powtórzenie Konstruktory i destruktory to specjalne funkcje składowe klasy Konstruktor wywoływany jest przy tworzeniu obiektu Konstruktor kopiujacy wywoływany jest przy tworzeniu kopii obiektu Destruktor wywoływany jest przed likwidacja obiektu K.Grzelak (Wykład 12) Programowanie w C++ 3 / 32
Konstruktor kopiujacy vs operator przypisania Tutaj uruchamiany jest konstruktor kopiujacy: Wektor2D v1; Wektor2D v2(v1); Wektor2D v3=v1; Tutaj działa operator przypisania (!): Wektor2D v1(0.5,0.2,1.5,0.8); Wektor2D v2; v2=v1; Wektor2D - klasa z poprzednich wykładów. K.Grzelak (Wykład 12) Programowanie w C++ 4 / 32
Przeładowanie operatorów - przypomnienie Przeładowanie operatorów to przedefiniowanie standardowych operatorów: +,,, /,... tak, żeby działały dla obiektów danej klasy. K.Grzelak (Wykład 12) Programowanie w C++ 5 / 32
Przeładowanie operatorów - przypomnienie Przeładowane operatory nie musza mieć znaczenia podobnego do oryginalnego, np.: + nie musi służyć do dodawania obiektów K.Grzelak (Wykład 12) Programowanie w C++ 6 / 32
Operator przypisania Operator przypisania służy do przypisania zawartości jednego obiektu klasy T drugiemu obiektowi tej klasy: T& T::operator=(T &); np. Wektor2D v1(0.5,0.2,1.5,0.8); Wektor2D v2; v2=v1; K.Grzelak (Wykład 12) Programowanie w C++ 7 / 32
Wskaźnik this Jeżeli używamy wskaźnika do obiektu danej klasy, to odwołanie do funkcji (i danych) składowych poprzez operator -> Przykład dla klasy liczb zespolonych Z z1; Z * wsk; wsk = &z1; cout «wsk->abs() «endl; this Wskaźnik do obiektu na rzecz którego została wywołana funkcja składowa. K.Grzelak (Wykład 12) Programowanie w C++ 8 / 32
Wskaźnik this Przykład: operator dodawania dla liczb zespolonych Z Z::operator+( const Z& z ) const { Z suma; suma.re = this->re + z.re; suma.im = this->im + z.im; return suma; } Tutaj this można pominać. K.Grzelak (Wykład 12) Programowanie w C++ 9 / 32
Wskaźnik this Przykład: operator przypisania dla liczb zespolonych Z& Z::operator=( const Z& z ) { this->re = z.re; this->im = z.im; return *this; } K.Grzelak (Wykład 12) Programowanie w C++ 10 / 32
Operator przypisania +=, wskaźnik this W przypadku operatora += (i jemu podobnych) wynikiem jest referencja do obiektu na rzecz którego wywoływana jest funkcja operator+= Przykład: operator += dla liczb zespolonych Z& Z::operator+=( const Z& z) { re+=z.re; im+=z.im; return *this; } K.Grzelak (Wykład 12) Programowanie w C++ 11 / 32
Operator przypisania Jeśli w definicji klasy nie ma zdefiniowanego operatora przypisania, to zostanie stworzony automatycznie. Kiedy to nie będzie wystarczajace: Przykład Wskaźnik do dynamicznej tablicy jest składnikiem obiektu Tablica nie jest częścia obiektu Przypisanie starego wskaźnika nowemu oznacza że oba obiekty będa korzystać z tej samej tablicy! Rozwiazanie: operator przypisania, który tworzy nowa tablicę (podobnie w przypadku konstruktora kopiujacego) K.Grzelak (Wykład 12) Programowanie w C++ 12 / 32
Dziedziczenie K.Grzelak (Wykład 12) Programowanie w C++ 13 / 32
Klasy pochodne i podstawowe Dziedziczenie = definiowanie nowej klasy przy wykorzystaniu wcześniej istniejacej klasy Klasa pochodna dziedziczy składniki (funkcjonalności!) klasy podstawowej, ale może mieć nowe dane i funkcje składowe. K.Grzelak (Wykład 12) Programowanie w C++ 14 / 32
Klasy pochodne i podstawowe Przykłady klas podstawowych i pochodnych: Klasa podstawowa Owoc Samochod ios ostream Klasy pochodne Jablko, Gruszka Kabriolet, SUV, TIR istream, ostream ofstream, ostringstream, iostream Podobieństwa pomiędzy praca z różnymi rodzajami strumieni nieprzypadkowe! K.Grzelak (Wykład 12) Programowanie w C++ 15 / 32
Podobieństwa pomiędzy różnymi strumieniami Strumienie: standard pliki napisy Pliki nagłówkowe #include<iostream> #include<fstream> #include<sstream> Zapisywanie do strumienia: ofstream p1( out.txt ); ostringstream s1; cout «a= «a «endl; p1 «a= «a «endl; s1 «a= «a «endl; string s=s1.str(); Czytanie ze strumienia: int a,c; string wyraz; ifstream p2( inp.txt ); istringstream s2( 15 maj 2018 ); cin» a» wyraz» c; p2» a» wyraz» c; s2» a» wyraz» c; Przykłady: while(true){ while(true){ istringstream s3(argv[1]); cin» liczba; p2» liczba; int n; if(cin.fail()){ if(p2.fail()){ s3» n; break; break; } } } } p2.close(); K.Grzelak (Wykład 12) Programowanie w C++ 16 / 32
Jak zdefiniować klasę która jest pochodna innej klasy Klasa podstawowa może wygladać np. tak: class Mebel { public: Mebel(string, int); int get_rok_produkcji() const ; void opis() const ;... private: string producent; int rok_produkcji; }; K.Grzelak (Wykład 12) Programowanie w C++ 17 / 32
Jak zdefiniować klasę która jest pochodna innej klasy Klasa pochodna od klasy Mebel może wygladać np. tak: class Komoda : public Mebel { public: Komoda(string, int, string); void opis() const ;... private: string model; int ile_szuflad; } Komoda jest rodzajem mebla. K.Grzelak (Wykład 12) Programowanie w C++ 18 / 32
Klasy pochodne i podstawowe - zasłanianie nazw W obu klasach moga być składniki o tej samej nazwie: składnik z klasy pochodnej zasłania odziedziczony składnik, ale do obu można się odwołać: Komoda k1; k1.opis(); k1.mebel::opis(); K.Grzelak (Wykład 12) Programowanie w C++ 19 / 32
Dziedziczenie składników różnego typu O czym decyduje klasa podstawowa, czyli w jaki sposób dziedziczone sa składniki public, protected i private: Klas pochodna nie ma dostępu tylko do prywatnych składników klasy podstawowej. K.Grzelak (Wykład 12) Programowanie w C++ 20 / 32
Dziedziczenie składników różnego typu Trzeci rodzaj typu składników klasy protected: składniki występujace w klasie podstawowej za słowem protected sa dostępne dla klas pochodnych jak publiczne. Dla innych sa jak prywatne. K.Grzelak (Wykład 12) Programowanie w C++ 21 / 32
Dziedziczenie składników różnego typu O czym decyduje klasa pochodna, czyli w jaki sposób klasa pochodna chce udostępniać światu dziedziczone składniki: W definicji klasy pochodnej: class Komoda : class Komoda : class Komoda : public Mebel protected Mebel private Mebel K.Grzelak (Wykład 12) Programowanie w C++ 22 / 32
Dziedziczenie składników różnego typu Można dziedziczyć po więcej niż jednej klasie: class Komoda : public Mebel, private Regal K.Grzelak (Wykład 12) Programowanie w C++ 23 / 32
Dziedziczenie Czy wszystko się dziedziczy? Nie. Klasa pochodna nie dziedziczy: prywatnych składników klasy podstawowej konstruktorów destruktorów operatorów przypisania K.Grzelak (Wykład 12) Programowanie w C++ 24 / 32
Dziedziczenie Klasa, która jest pochodna jednej klasy, sama może być klasa podstawowa innej klasy, np.: ios ostream ofstream K.Grzelak (Wykład 12) Programowanie w C++ 25 / 32
Kolejność w jakiej wywoływane sa konstruktory Kolejność uruchamiania: 1 konstruktory obiektów będacych składnikami klasy podstawowej 2 konstruktor klasy podstawowej 3 konstruktory obiektów będacych składnikami klasy pochodnej 4 konstruktor klasy pochodnej K.Grzelak (Wykład 12) Programowanie w C++ 26 / 32
Jeszcze o konstruktorach Na liście inicjalizacyjnej konstruktora klasy pochodnej można umieścić wywołanie konstruktora klasy podstawowej. K.Grzelak (Wykład 12) Programowanie w C++ 27 / 32
Przykład Klasa podstawowa class Zwierze { public: Zwierze(){ } Zwierze(string nazwa) {gromada=nazwa;}... protected: string gromada; string gatunek; string imie; int rok_urodzenia; }; K.Grzelak (Wykład 12) Programowanie w C++ 28 / 32
Przykład Klasa pochodna class Kot : public Zwierze { public: Kot(){} Kot(string nazwa); string getgromada() const {return gromada;} string getgatunek() const {return gatunek;}... }; Kot::Kot(string nazwa) : Zwierze( ssak ) { imie=nazwa; gatunek= kot_domowy ; } K.Grzelak (Wykład 12) Programowanie w C++ 29 / 32
Przykład Program int main(){ Kot kot1( Filemon ); cout «gromada= «kot1.getgromada() «endl; cout «gatunek= «kot1.getgatunek() «endl; return 0; } K.Grzelak (Wykład 12) Programowanie w C++ 30 / 32
Zalety dziedziczenia Unikanie wielokrotnego pisania tych samych lub podobnych fragmentów kodu Możliwość dostosowania kodu do zmieniajacych się wymagań bez zmiany głównej części programu Możliwość tworzenia hierarchii klas, wyrażanie zależności między klasami... K.Grzelak (Wykład 12) Programowanie w C++ 31 / 32
Jeszcze o operatorach Przykład: przeładowany operator «z klasy Ulamek ostream& operator«(ostream& os, const Ulamek& u1){ os «u1.licznik «/ «u1.mianownik «endl; return os; } Tak zdefiniowany operator działa dla wszystkich strumieni wywodzacych się z klasy ostream, czyli dla iostream, ofstream, ostringstream K.Grzelak (Wykład 12) Programowanie w C++ 32 / 32