1 / 14

Programowanie obiektowe

Programowanie obiektowe. Wykład 6. Programowanie obiektowe Wykład 6 Dziedziczenie III (C++). Dariusz Wardowski. d r Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ. Programowanie obiektowe. Wykład 6. Wirtualne destruktory. class A { private : int * a; public:

illana-wong
Download Presentation

Programowanie obiektowe

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Programowanie obiektowe Wykład 6 Programowanie obiektowe Wykład 6 Dziedziczenie III (C++) Dariusz Wardowski dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  2. Programowanie obiektowe Wykład 6 Wirtualne destruktory class A { private: int* a; public: A(int _a) {a = newint(_a);} virtual ~A() {delete a;} }; class B: public A { private: double* b; public: B(int _a, double _b): A(_a){ b = new double(_b);} virtual ~B() {delete b;} }; intmain() { A* wsk1 = new A(3); A* wsk2 = new B(4,2.9); delete wsk1; //działa destruktor ~A() delete wsk2; //działają kolejno //destruktory ~B(), ~A(). return 0; } Poprzedzenie destruktorów słowem virtual powoduje, że podczas destrukcji obiektu zostanie wywołany odpowiedni kod destruktora. Jeżeli wskaźnik (referencja) wskazuje na obiekt typu B, wówczas nastąpi wywołanie destruktora ~B() klasy potomnej, a następnie ~A() klasy macierzystej. Innymi słowy, wykorzystanie wirtualnych destruktorów zapewnia odpowiednią kolejność ich wywołania. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  3. Programowanie obiektowe Wykład 6 Wiązanie statyczne i dynamiczne Wiązanie nazwy funkcji polega na określeniu odpowiedniego bloku wykonywalnego (w kodzie skompilowanym), który ma zostać użyty. Wiązanie statyczne to wiązanie, które jest realizowane podczas kompilacji kodu źródłowego. Wiązanie dynamiczne, to odpowiedni mechanizm, który pozwala wybrać odpowiednią metodę wirtualną podczas działania programu. Uwaga Wiązanie dynamiczne zachodzi wówczas, gdy odpowiednie metody wywoływane są przez wskaźniki lub referencje. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  4. Programowanie obiektowe Wykład 6 Rzutowanie w górę Rzutowanie w górę jest to konwersja referencji (wskaźnika) do klasy potomnej na referencję (wskaźnik) do klasy macierzystej. Podczas dziedziczenia publicznego konwersja taka jest zawsze możliwa i zachodzi bez jawnego rzutowania typów. A* wsk = newB(3,4.5); A & ref = B(4,4.3); Bb(3,4.5); A & ref = b; Wszelkie metody jakie można wykonywać na obiekcie klasy A, można wykonywać na obiekcie klasy B. Funkcja, której argumentem jest wskaźnik (referencja) do obiektu klasy A, będzie działać na obiekcie klasy B. Rzutowanie w górę jest przechodnie. Tzn. w przypadku, gdy klasa B dziedziczy z A, a klasa C dziedziczy z B, wówczas wskaźniki (referencje) do klasy A, mogą dotyczyć obiektów zarówno klasy B jak i C. A* a, b; a = new B(); b = new C(); dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  5. Programowanie obiektowe Wykład 6 Rzutowanie w dół Rzutowanie w dół polega na konwersji referencji lub wskaźnika do klasy macierzystej na referencję lub wskaźnik do klasy potomnej. Rzutowanie w dół nie jest wykonywane bez jawnej konwersji typów. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  6. Programowanie obiektowe Wykład 6 Funkcje wirtualne – podsumowanie • Jeżeli w deklaracji klasy daną metodę poprzedzimy słowem kluczowym virtual, wówczas metoda będzie metodą wirtualną w klasie macierzystej, potomnej i innych klasach dziedziczących po klasie potomnej. • Jeżeli metoda wirtualna wywoływana jest na rzecz referencji lub wskaźnika, to program użyje tej wersji metody, która odpowiada typowi obiektu na który dana referencja czy wskaźnik wskazuje. • Na metody wirtualne wybieramy te, które w klasach potomnych będą przedefiniowane. • Jeżeli w którejś klasie potomnej nie zostanie przedefiniowana metoda wirtualna, wówczas obiekt tej klasy będzie korzystał z funkcji wirtualnej najbliższego „przodka”. • Konstruktory nie mogą być metodami wirtualnymi, gdyż klasa potomna nie dziedziczy konstruktorów klasy macierzystej. • Jeżeli dana klasa będzie stanowić klasę macierzystą, wówczas jej destruktory powinny być wirtualne. • Funkcje zaprzyjaźnione nie mogą być wirtualne, gdyż nie są metodami klasowymi. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  7. Programowanie obiektowe Wykład 6 Kontrola dostępu • Do kontrolowania dostępu do pól składowych klasy stosujemy słowa kluczowe: • public • private • protected Składowe chronione, czyli te które umieszczone są w sekcji protected, nadal dostępne są tylko dla metod tej samej klasy. Mogą być one udostępnione poza klasą tylko przy pomocy publicznych metod udostępniających te dane (analogiczne jak private). class A { private: int x; protected: double y; public: intgetX(); double getY(); }; dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  8. Programowanie obiektowe Wykład 6 protected class A { private: int x; protected: double y; public: intgetX(); double getY(); }; class B: public A { public: voidsetY(double _y) { y = _y; } }; Klasa B ma bezpośredni dostęp do składowej y. W wyniku metody setY(double) „psuje się” enkapuslacja tej zmiennej. Najlepiej umieszczać w sekcji protected te pola składowe, do których dostęp w klasie potomnej jest możliwy tylko za pomocą interfejsu publicznego klasy macierzystej. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  9. Programowanie obiektowe Wykład 6 Klasa Rownoleglobok – macierzysta czy nie? classRownoleglobok { private: double a; double h; double alfa; public: double pole() const; double obwod() const; voidzmienKat(double a); }; Każdy prostokąt jest równoległobokiem, zatem czy jest sens klasę Prostokat wyprowadzić za pomocą dziedziczenia z klasy Rownoleglobok? dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  10. Programowanie obiektowe Wykład 6 Relacja „jest” a dziedziczenie classProstokat : public Rownoleglobok { … }; • Wady klasy Prostokat: • Do opisania prostokąta mamy trzy pola składowe (alfa zbędne, bo zawsze 90). • Dziedziczona metoda zmienKat() nie ma dla prostokąta sensu, gdyż obiekt przestanie być prostokątem. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  11. Programowanie obiektowe Wykład 6 Może jednak bez dziedziczenia? classRownoleglobok { private: double a; double h; double alfa; public: double pole() const; double obwod() const; voidzmienKat(double a); }; classProstokat { private: double a; double h; public: double pole() const; double obwod() const; }; Deklaracja klasy Prostokat posiada już tylko te pola i metody składowe, które są potrzebne. Wydaje się jednak, że z uwagi na widoczny wspólny kod tych klas, można wprowadzić inne rozwiązanie. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  12. Programowanie obiektowe Wykład 6 Abstrakcyjna klasa macierzysta Rozwiązanie to polega na wyodrębnieniu wspólnych cech tych klas i umieszczeniu ich w tzw. abstrakcyjnej klasie macierzystej, po której klasy Prostokat i Rownoleglobok będą dziedziczyły. classAbstrRownoleglobok { private: double a; double h; public: AbstrRownoleglobok(double _a = 0, double _h = 0) : a(_a), h(_h) {}; virtual ~AbstrRownoleglobok() {}; double pole() const {return a*h;} virtual double obwod() const = 0; //funkcja w pełni wirtualna }; Z uwagi na brak danych, nie można zaimplementować metody obwod(). Dodanie „= 0” na końcu deklaracji metody wirtualnej powoduje, że metoda ta staje się w pełni wirtualna, a w konsekwencji klasa AbstrRowoleglobok jest abstrakcyjna (tzn. posiada co najmniej jedną metodę w pełni wirtualną). dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  13. Programowanie obiektowe Wykład 6 Zastosowanie klas abstrakcyjnych • Nie można tworzyć obiektów klasy abstrakcyjnej: • AbstRownoleglobokap; //błąd! • AbstRownoleglobok * wsk; //OK • Klasy abstrakcyjne służą jako klasy macierzyste, a więc tworzymy je po to by z nich dziedziczyć. • classRownoleglobok: public AbstRownoleglobok • { • … • }; • classProstokat: public AbstRownoleglobok • { • … • }; • Mechanizm abstrakcyjnych klas macierzystych pozwala projektować hierarchię klas w sposób bardziej usystematyzowany i zdyscyplinowany. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

  14. Programowanie obiektowe Wykład 6  Dziękuję za uwagę dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

More Related