Programowanie w C++ Wykład 14 Katarzyna Grzelak 3 czerwca 2019 K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27
Na ostatnim wykładzie: Konstruktor standardowy (domyślny) to taki, który nie ma żadnych argumentów lub wszystkie jego argumenty sa domyślne. K.Grzelak (Wykład 14) Programowanie w C++ 2 / 27
Na ostatnim wykładzie: Lista inicjalizacyjna służy m.in. do inicjalizowania obiektów const i obiektów innej klasy, które sa danymi składowymi klasy. class F{ public: F(int liczba); private: double x; double y; const int k; G element; ; F::F(int liczba):x(0),y(0),k(100),element(liczba,ćzerwony"){ K.Grzelak (Wykład 14) Programowanie w C++ 3 / 27
Z ostatniego wykładu: co się wypisze na ekranie? class Punkt{ public: Punkt(double x=5, double y=15.5); void wypisz(); private: double x; double y; ; Punkt::Punkt(double x, double y){ void Punkt::wypisz(){ cout << "(" << x << "," << y << ")" << endl; int main(){ Punkt p; p.wypisz(); return 0; K.Grzelak (Wykład 14) Programowanie w C++ 4 / 27
Wersja poprawna (z użyciem listy inicjalizacyjnej) class Punkt{ public: Punkt(double, double); void wypisz(); private: double x; double y; ; Punkt::Punkt(double wsp1, double wsp2):x(wsp1),y(wsp2){ void Punkt::wypisz(){ cout << "(" << x << "," << y << ")" << endl; int main(){ Punkt p; p.wypisz(); return 0; K.Grzelak (Wykład 14) Programowanie w C++ 5 / 27
Wersja z operatorem«chcielibyśmy tak używać klasy Punkt: int main(){ Punkt p; cout << p << endl; return 0; K.Grzelak (Wykład 14) Programowanie w C++ 6 / 27
Wersja z operatorem«chcielibyśmy tak używać klasy Punkt: int main(){ Punkt p; cout << p << endl; ofstream plik("punkty.txt"); plik << p << endl; plik.close(); return 0; Konieczne jest przeładowanie operatora «K.Grzelak (Wykład 14) Programowanie w C++ 7 / 27
Wersja z operatorem«class Punkt{ public: Punkt(double, double); void wypisz(); friend ostream & operator<<(ostream & os, const Punkt & p private: double x; double y; ; Punkt::Punkt(double wsp1, double wsp2):x(wsp1),y(wsp2){ void Punkt::wypisz(){ cout << "(" << x << "," << y << ")" << endl; ostream & operator<<(ostream & os, const Punkt & p){ os << "(" << p.x << "," << p.y << ")"; return os; K.Grzelak (Wykład 14) Programowanie w C++ 8 / 27
Na ostatnim wykładzie cd: Statyczna dana składowa klasy: deklaracja wewnatrz definicji klasy: static int licznik; definicja poza definicja klasy: int NazwaKlasy::licznik=0; jest tworzona w pamięci tylko raz i jest wspólna dla wszystkich obiektów tej samej klasy. K.Grzelak (Wykład 14) Programowanie w C++ 9 / 27
Z ostatniego wykładu, standard C++11 Modyfikacja pętli for i auto vector<double> liczby(10,-1.5); //Sumowanie kolejnych elementów wektora: double suma=0; for (auto elem : liczby){ suma+=elem; //Modyfikacja wektora (mnożenie przez 2): for (auto &elem : liczby){ elem*=2; K.Grzelak (Wykład 14) Programowanie w C++ 10 / 27
Dwa sposoby odwoływania się do funkcji składowych klasy Przykład dla klasy liczb zespolonych Z Z z1; Z* wsk; wsk = &z1; z1.abs() wsk->abs() K.Grzelak (Wykład 14) Programowanie w C++ 11 / 27
Dziedziczenie Dziedziczenie = definiowanie nowej klasy przy wykorzystaniu wcześniej istniejacej klasy Klasa podstawowa klasa od której się dziedziczy Klasa pochodna klasa dziedziczaca K.Grzelak (Wykład 14) Programowanie w C++ 12 / 27
Funkcje wirtualne przykład bez nich Przykład z Symfonii C++ Grębosza Klasa podstawowa class instrument{ public: void wydaj_dzwiek() { cout << "Nieokreślony brzdęk" << endl; private: int cena; string producent; ; K.Grzelak (Wykład 14) Programowanie w C++ 13 / 27
Funkcje wirtualne przykład bez nich Klasy pochodne class trabka: public instrument{ public: void wydaj_dzwiek(){ cout << "Tu-tu-tu" << endl; ; class beben: public instrument{ public: void wydaj_dzwiek(){ cout << "Bum-bum-bum" << endl; ; class fortepian: public instrument{ public: void wydaj_dzwiek(){ cout << "Plim-plim-plim" << endl; ; K.Grzelak (Wykład 14) Programowanie w C++ 14 / 27
Funkcje wirtualne przykład bez nich Funkcja main int main(){ instrument niezidentyfikowany_instrument; trabka zlota_trabka; fortepian steinway; beben bebenek; niezidentyfikowany_instrument.wydaj_dzwiek(); zlota_trabka.wydaj_dzwiek(); steinway.wydaj_dzwiek(); bebenek.wydaj_dzwiek(); K.Grzelak (Wykład 14) Programowanie w C++ 15 / 27
Funkcje wirtualne przykład bez nich Na ekranie: Nieokreślony brzdęk Tu-tu-tu Plim-plim-plim Bum-bum-bum K.Grzelak (Wykład 14) Programowanie w C++ 16 / 27
Funkcje wirtualne przykład bez nich Funkcja main, użycie wskaźników int main(){ instrument niezidentyfikowany_instrument; trabka zlota_trabka; fortepian steinway; beben bebenek; instrument *wskinstr; wskinstr = &niezidentyfikowany_instrument; wskinstr->wydaj_dzwiek(); wskinstr=&zlota_trabka; wskinstr->wydaj_dzwiek(); wskinstr=&steinway; wskinstr->wydaj_dzwiek(); wskinstr=&bebenek; wskinstr->wydaj_dzwiek(); K.Grzelak (Wykład 14) Programowanie w C++ 17 / 27
Dygresja: niejawna zamiana typów Przykłady: double liczba=15; char znak=97; Uwaga double liczba=1/2; K.Grzelak (Wykład 14) Programowanie w C++ 18 / 27
Dygresja: niejawna zamiana typów Wskaźnik do obiektu klasy podstawowej może być użyty do pokazania obiektu klasy pochodnej. Niejawna zamiana typów: wskaźnik klasy pochodnej może być zamieniony na wskaźnik (jednoznacznej) klasy podstawowej. K.Grzelak (Wykład 14) Programowanie w C++ 19 / 27
Funkcje wirtualne Na ekranie - wersja ze wskaźnikami: Nieokreślony brzdęk Nieokreślony brzdęk Nieokreślony brzdęk Nieokreślony brzdęk Program działa, ale we wszystkich przypadkach wywoływana jest funkcja składowa klasy podstawowej. K.Grzelak (Wykład 14) Programowanie w C++ 20 / 27
Funkcje wirtualne Druga wersja klasy podstawowej class instrument{ public: virtual void wydaj_dzwiek() { cout << "Nieokreślony brzdęk" << endl; private: int cena; string producent; ; K.Grzelak (Wykład 14) Programowanie w C++ 21 / 27
Funkcje wirtualne Przykład z Symfonii C++ Grębosza Teraz na ekranie (w wersji ze wskaźnikami): Nieokreślony brzdęk Tu-tu-tu Plim-plim-plim Bum-bum-bum Jeżeli w klasie podstawowej funkcja ma przedrostek virtual, to kompilator sprawdza na co wskaźnik pokazuje. Orientuje się według typu obiektu uruchamia funkcję z klasy obiektu pokazywanego przez wskaźnik. K.Grzelak (Wykład 14) Programowanie w C++ 22 / 27
Funkcje wirtualne Podobnie jest z referencjami: void muzyk(instrument & powierzony_instrument); int main(){ instrument niezidentyfikowany_instrument; trabka zlota_trabka; fortepian steinway; beben bebenek; muzyk(niezidentyfikowany_instrument); muzyk(zlota_trabka); muzyk(steinway); muzyk(bebenek); // Funkcja globalna void muzyk(instrument & powierzony_instrument){ powierzony_instrument.wydaj_dzwiek(); K.Grzelak (Wykład 14) Programowanie w C++ 23 / 27
Funkcje wirtualne Teraz na ekranie (w wersji z referencjami): Nieokreślony brzdęk Tu-tu-tu Plim-plim-plim Bum-bum-bum K.Grzelak (Wykład 14) Programowanie w C++ 24 / 27
Polimorfizm Polimorfizm (wielość-form) W funkcji muzyk linijka: powierzony_instrument.wydaj_dzwiek(); efektywnie wywoływana jako: powierzony_instrument.instrument::wydaj_dzwiek(); lub powierzony_instrument.trabka::wydaj_dzwiek(); lub powierzony_instrument.fortepian::wydaj_dzwiek(); lub powierzony_instrument.beben::wydaj_dzwiek(); K.Grzelak (Wykład 14) Programowanie w C++ 25 / 27
Polimorfizm Polimorfizm Polimorfizm = wielość form Polimorfizm ujawnia się tam, gdzie jest wywoływana funkcja wirtualna Klasa polimorficzna zawiera (lub dziedziczy) funkcję wirtualna K.Grzelak (Wykład 14) Programowanie w C++ 26 / 27
Polimorfizm Polimorfizm - po co? Dodawanie nowych klas będacych klasami pochodnymi od uprzednio istniejacej klasy jest znacznie prostsze. K.Grzelak (Wykład 14) Programowanie w C++ 27 / 27