Programowanie obiektowe w C++ Wykªad 4 dr Lidia St pie«akademia im. Jana Dªugosza w Cz stochowie L. St pie«(ajd) Programowanie obiektowe w C++ 1 / 26
Dziedziczenie - podstawy Denicja klasy dziedzicz cej w sposób publiczny po innej klasie: class Pochodna : public Bazowa { // tre± klasy Klasa pochodna dziedziczy po klasie bazowej jej pola i funkcje skªadowe. Klasa pochodna oprócz wªasnych skªadowych b dzie zatem posiadaªa równie» skªadowe z klasy Bazowa. L. St pie«(ajd) Programowanie obiektowe w C++ 2 / 26
Przykªad 1 class Samochod{ Samochod(); void Info() const; bool osobowy; class Fiat : public Samochod{ Fiat(); class Star : public Samochod{ Star(); L. St pie«(ajd) Programowanie obiektowe w C++ 3 / 26
Przykªad 1 cd. Samochod::Samochod(){ void Samochod::Info() const { if osobowy cout << "Samochod sobowy" << endl; else cout << "Samochod ciezarowy" << endl; Fiat:: Fiat(){ osobowy = true; Star:: Star(){ osobowy = false; L. St pie«(ajd) Programowanie obiektowe w C++ 4 / 26
Przykªad 1 cd. int main(){ Fiat a1; cout << "Samochod: "; a1.info(); Star a2; cout << "Samochod: "; a2.info(); // Naruszenie hermetyzacji a2.osobowy = true; return 0; L. St pie«(ajd) Programowanie obiektowe w C++ 5 / 26
Skªadowe prywatne i chronione w klasie bazowej Specykatora private u»ywamy, gdy chcemy uchroni skªadowe zarówno przed dost pem z zewn trz, jak i przed dost pem w klasach pochodnych. Specykatora protected u»ywamy, gdy chcemy uchroni skªadowe przed dost pem z zewn trz, ale jednocze±nie mie je do dyspozycji w klasach pochodnych. L. St pie«(ajd) Programowanie obiektowe w C++ 6 / 26
Rodzaje dziedziczenia W dziedziczeniu publicznym skªadowe publiczne klasy bazowej s dziedziczone jako publiczne, a skªadowe chronione jako chronione. W dziedziczeniu chronionym skªadowe publiczne oraz chronione s dziedziczone jako chronione. W dziedziczeniu prywatnym skªadowe publiczne oraz chronione s dziedziczone jako prywatne. Gdy nie jest podany typ dziedziczenia, to domy±lne jest dziedziczenie prywatne. Skªadowe prywatne s zawsze dziedziczone jako prywatne. L. St pie«(ajd) Programowanie obiektowe w C++ 7 / 26
Dziedziczenie a konstruktory Podczas tworzenia obiektu klasy pochodnej wywoªywany jest konstruktor domy±lny klasy bazowej, o ile taki konstruktor istnieje. Je»eli w klasie bazowej nie istnieje konstruktor domy±lny, nale»y jawnie wywoªa jeden z pozostaªych konstruktorów. Jawne wywolanie konstruktora klasy bazowej: Pochodna::Pochodna(argumenty) : Bazowa(argumenty) { // tre± konstruktora L. St pie«(ajd) Programowanie obiektowe w C++ 8 / 26
Przykªad 2 class Samochod{ Samochod(bool); void Info() const; protected: bool osobowy; class Fiat : public Samochod{ Fiat(); void Info() const; class Star : public Samochod{ Star(); void Info() const; L. St pie«(ajd) Programowanie obiektowe w C++ 9 / 26
Przykªad 2 cd. Samochod::Samochod(bool osobowy) : osobowy(osobowy){ void Samochod::Info() const { if osobowy cout << "Samochod sobowy" << endl; else cout << "Samochod ciezarowy" << endl; Fiat:: Fiat() : Samochod(true){ void Fiat::Info() const { Samochod::Info(); cout << "Fiat" << endl; Star:: Star() : Samochod(false){ void Star::Info() const { Samochod::Info(); cout << "Star" << endl; L. St pie«(ajd) Programowanie obiektowe w C++ 10 / 26
Przykªad 2 cd. int main(){ Fiat a1; cout << "Samochod: "; a1.info(); a1.samochod::info(); Star a2; cout << "Samochod: "; a2.info(); a2.samochod::info(); return 0; L. St pie«(ajd) Programowanie obiektowe w C++ 11 / 26
UWAGI W pierwszej kolejno±ci tworzony jest obiekt klasy bazowej. Konstruktor klasy pochodnej powinien przekazywa dane klasy bazowej do jej konstruktora za pomoc listy inicjalizacyjnej. Konstruktor klasy pochodnej powinien inicjalizowa wszystkie dane skªadowe, które zostaªy dodane do tej klasy. Kiedy obiekt klasy pochodnej jest usuwany, najpierw wywoªywany jest destruktor klasy pochodnej, a nast pnie destruktor klasy bazowej. Mo»na deklarowa referencje oraz wska¹niki do obiektów klasy bazowej i przypisywa im zarówno obiekty klasy bazowej, jak i pochodnej. Ale nie na odwrót! L. St pie«(ajd) Programowanie obiektowe w C++ 12 / 26
Przesªanianie pól i metod Gdy w klasie pochodnej znajduje si metoda f o takiej samej nazwie i argumentach jak metoda znajduj ca si w klasie bazowej, to mamy do czynienia ze zjawiskiem nadpisania metody. Aby wywoªa w klasie pochodnej nadpisan metod f z klasy bazowej nale»y u»y konstrukcji: Bazowa :: f (argumenty). Gdy w klasie pochodnej znajduje si pole p o takiej samej nazwie jak pole znajduj ce si w klasie bazowej, to mamy do czynienia ze zjawiskiem przesªoni tego pola. Aby w klasie pochodnej odwoªa si do przesªoni tego pola p z klasy bazowej nale»y u»y konstrukcji: Bazowa :: p. L. St pie«(ajd) Programowanie obiektowe w C++ 13 / 26
Przykªad 3 Niech A b dzie klas bazow, B jest klas dziedzicz c publicznie po A, f () jest niestatyczn metod z klasy A oraz f () jest nadpisana w klasie B. Zaªó»my,»e dane s deklaracje: B b; A& r = b; A* p = &b; Która z metod f () (z klasy bazowej czy pochodnej) zostanie wywoªana? b.f(); r.f(); p->f(); L. St pie«(ajd) Programowanie obiektowe w C++ 14 / 26
Metody wirtualne Aby metoda klasy staªa si wirtualna, nale»y jej nagªówek w deklaracji klasy poprzedzi sªowem kluczowym virtual. Metody wirtualne stosujemy wtedy, kiedy wiemy,»e w klasie pochodnej b dziemy powtórnie j deniowa. Wirtualno± pozwala wybra wersj metody na podstawie typu obiektu zamiast na podstawie typu referencji lub wska¹nika. Deklaracja metody w klasie bazowej za pomoc sªowa kluczowego virtual powoduje,»e funkcja ta jest wirtualna zarówno w klasie bazowej, jak i we wszystkich klasach od niej pochodnych (ª cznie z klasami pochodnymi klas pochodnych). L. St pie«(ajd) Programowanie obiektowe w C++ 15 / 26
Przykªad 3 class Samochod{ Samochod(bool); virtual void Info() const; protected: bool osobowy; class Fiat : public Samochod{ Fiat(); virtual void Info() const; class Star : public Samochod{ Star(); virtual void Info() const; L. St pie«(ajd) Programowanie obiektowe w C++ 16 / 26
Przykªad 3 cd. Samochod::Samochod(bool osobowy) : osobowy(osobowy){ void Samochod::Info() const { if osobowy cout << "Samochod sobowy" << endl; else cout << "Samochod ciezarowy" << endl; Fiat:: Fiat() : Samochod(true){ void Fiat::Info() const { Samochod::Info(); cout << "Fiat" << endl; Star:: Star() : Samochod(false){ void Star::Info() const { Samochod::Info(); cout << "Star" << endl; L. St pie«(ajd) Programowanie obiektowe w C++ 17 / 26
Przykªad 3 cd. int main(){ Samochod *ps = new Fiat; cout << "Samochod: "; ps->info(); Star a2; Samochod &rs = a2; cout << "Samochod: "; rs.info(); return 0; L. St pie«(ajd) Programowanie obiektowe w C++ 18 / 26
Metody wirtualne Konstruktory nie mog by wirtualne. Tworzenie obiektu klasy pochodnej wymaga wywoªania konstruktora klasy pochodnej, a nie bazowej. Konstruktor klasy pochodnej u»ywa konstruktora klasy bazowej, a nie dziedziczy go. Nie ma wi c powodu, aby tworzy konstruktory wirtualne. Je±li klasa ma by wykorzystywana jako bazowa, to destruktory powinny by wirtualne. A *pa = new B;... delete pa; // poprawnie; A to klasa bazowa B // ~A() czy ~B()? Powinno si udost pnia w klasie bazowej destruktor wirtualny, nawet wtedy kiedy klasa ta nie potrzebuje destruktora. L. St pie«(ajd) Programowanie obiektowe w C++ 19 / 26
UWAGI Funkcje zaprzyja¹nione nie mog by wirtualne, poniewa» nie s skªadowymi klasy, a tylko funkcje skªadowe mog by wirtualne. Mo»na u»y metod wirtualnych wewnatrz funkcji zaprzyja¹nionych i w ten sposób obej± powy»sze ograniczenie. Je±li w klasie pochodnej nie ma nowej denicji funkcji, wtedy klasa u»ywa wersji tej funkcji z klasy bazowej. Je»eli klasa jest ogniwem dªugiego ªa«cucha dziedziczenia, wtedy u»ywa wersji tej funkcji zdeniowanej najbli»ej. L. St pie«(ajd) Programowanie obiektowe w C++ 20 / 26
Ukrywanie metod w wyniku powtórnej denicji class A{ virtual void show(int) const;... class B : public A{ virtual void show() const;... B b; b.show(); b.show(5); // poprawne // niepoprawne L. St pie«(ajd) Programowanie obiektowe w C++ 21 / 26
UWAGI W wyniku powtórnej denicji funkcji skªadowej w klasie pochodnej ró»ni cej si argumentem, powstaje jedna wersja tej funkcji, a nie dwie przeci»one. Funkcja z klasy bazowej zostaje ukryta. Nowa denicja ukrywa wszystkie metody klasy bazowej o tej samej nazwie, niezaleznie od ich sygnatur. Je±li redeniujemy odziedziczon metod, musi ona dokªadnie pasowa do prototypu funkcji z klasy bazowej. Istnieje mozliwo± zmiany zwracanego przez funkcj typu ze wska¹nika lub referencji klasy bazowej na wska¹nik lub referencj klasy pochodnej. Jest to kowariancja zwracanego typu. Je±li deklaracja funkcji w klasie bazowej jest przeci»ona, to w klasie pochodnej musimy powtórnie zdeniowa wszystkie wersje z klasy bazowej. L. St pie«(ajd) Programowanie obiektowe w C++ 22 / 26
Abstrakcyjne klasy bazowe W j zyku C++ istnieje sposób na umieszczenie funkcji bez implementacji w postaci funkcji czysto wirtualnej. Funkcja czysto wirtualna ma wyra»enie = 0 na ko«cu deklaracji. Aby klasa byªa prawdziw klas czysto abstrakcyjn, musi mie przynajmniej jedn funkcj czysto wirtualn. Je±li klasa zawiera metod czysto wirtualn, nie mo»emy tworzy obiektów tej klasy. St d klasy te s wykorzystywane jedynie jako klasy bazowe. Ka»d metod czysto wirtualn klasy bazowej nale»y przeci»y w klasie pochodnej, w przeciwnym przypadku klasa pochodna nadal pozostanie czysto abstrakcyjn. L. St pie«(ajd) Programowanie obiektowe w C++ 23 / 26
override - w C++11 oznacza,»e dana metoda w klasie pochodnej przesªania metod wirtualn z klasy bazowej class B { virtual void x() { class D : public B { virtual void x() override { //OK class E : public B { virtual void x() const override { //Bª d class F : public B { virtual void y() override { //Bª d L. St pie«(ajd) Programowanie obiektowe w C++ 24 / 26
Przykªad 4 class Ksztalt { virtual ~Ksztalt() { virtual void rysuj() = 0; //ka»dy okre±lony //ksztaªt musi da sie narysowa class Kolo : public Ksztalt { virtual void rysuj() { std::cout << "Rysuje kolo: ( )" << std::endl; class Kwadrat : public Ksztalt { virtual void rysuj() { std::cout << "Rysuje kwadrat: [ ]" << std::endl; L. St pie«(ajd) Programowanie obiektowe w C++ 25 / 26
Przykªad 4 cd. int main(){ //Ksztalt a; Ksztalt * a = new Kolo, * b = new Kwadrat; a->rysuj(); b->rysuj(); delete a; delete b; L. St pie«(ajd) Programowanie obiektowe w C++ 26 / 26