Programowanie obiektowe w C++ Wykład 4
Transkrypt
Programowanie obiektowe w C++ Wykład 4
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{ public: Samochod(); void Info() const; bool osobowy; }; class Fiat : public Samochod{ public: Fiat(); }; class Star : public Samochod{ public: 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{ public: Samochod(bool); void Info() const; protected: bool osobowy; }; class Fiat : public Samochod{ public: Fiat(); void Info() const; }; class Star : public Samochod{ public: 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¦ nale»y u»y¢ konstrukcji: Bazowa :: f (argumenty ). f z klasy bazowej 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 bazowej nale»y u»y¢ konstrukcji: Bazowa :: p . L. St¦pie« (AJD) Programowanie obiektowe w C++ p z klasy 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{ public: Samochod(bool); virtual void Info() const; protected: bool osobowy; }; class Fiat : public Samochod{ public: Fiat(); virtual void Info() const; }; class Star : public Samochod{ public: 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; // poprawnie; A to klasa bazowa B .... delete pa; // ~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{ public: virtual void show(int) const; ... }; class B : public A{ public: virtual void show() const; ... }; B b; b.show(); // poprawne b.show(5); // 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 { public: virtual ~Ksztalt() { } virtual void rysuj() = 0; //ka»dy okre±lony //ksztaªt musi da¢ sie narysowa¢ }; class Kolo : public Ksztalt { public: virtual void rysuj() { std::cout << "Rysuje kolo: ( )" << std::endl; } }; class Kwadrat : public Ksztalt { public: 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