190 likes | 292 Views
Zachodniopomorska Szkoła Biznesu. Podstawy programowania II. Wykład 7: Dziedziczenie. Kiedy przydatne jest dziedziczenie?. Wyobraźmy sobie, że mamy napisaną świetnie działającą klasę Osoba służącą do obsługi danych osobowych.
E N D
Zachodniopomorska Szkoła Biznesu Podstawy programowania II Wykład 7: Dziedziczenie
Kiedy przydatne jest dziedziczenie? • Wyobraźmy sobie, że mamy napisaną świetnie działającą klasę Osoba służącą do obsługi danych osobowych. • Chcemy teraz napisać klasę Student służącą do przetwarzania danych studenta uczelni (w tym danych osobowych). • Naturalną myślą jest pytanie o możliwość wykorzystania gotowej klasy Osoba do obsługi danych osobowych studenta, co pozwoli ograniczyć się do oprogramowania właściwości klasy Student niezwiązanych z danymi osobowymi. • W takiej sytuacji z pomocą przychodzi mechanizm dziedziczenia, pozwalający przy tworzeniu klasy, zwanej potomną, wykorzystać właściwości i metody innej, wcześniej utworzonej klasy, zwanej bazową. Podstawy programowania II - Dziedziczenie
Istota dziedziczenia • Dziedziczenie polega na definiowaniu klasy potomnej w oparciu o klasę bazową na zasadzie:Klasa Potomna = Klasa Bazowa+ Nowe Elementy • Klasa potomna ma więc wszystkie właściwości i metody klasy bazowej oraz dodatkowe, własne właściwości i metody. • Można powiedzieć, że klasa potomna jest rodzajem (lub podklasą) klasy bazowej • Dziedziczenie jest możliwe nawet wtedy, jeżeli klasa bazowa napisana była przez kogoś innego i dostępna jest na przykład w postaci biblioteki i nie mamy jej pełnego kodu źródłowego!!!.Niezbędna jest tylko jej deklaracja (zwykle w pliku .H) Podstawy programowania II - Dziedziczenie
Dziedziczenie w C++ • Składnia deklaracji klasy potomnejclass Potomna : [tryb dostępu] Bazowa{ // deklaracje składników klasy potomnej}; • Bazowa musi być nazwą znanej wcześniej klasy • tryb dostępuprivate (domyślnie), protected lub public • Wewnątrz funkcji klasy Potomna można używać składników klasy Bazowa tak jakby były jej własnymi (z wyjątkiem składników prywatnych klasy Bazowa) Podstawy programowania II - Dziedziczenie
Przykład dziedziczenia class Bazowa { public:int baza;void wypiszBazowa(){ cout << "baza=" << baza; } }; class Potomna : public Bazowa { public:float dodatek;void wypiszPotomna(){ wypiszBazowa(); cout << "dodatek=" << dodatek;} }; Przykład: DZIEDZICZENIE1.CPP Bazowa: bazawypiszBazowa() Potomna: baza dodatekwypiszBazowa()wypiszPotomna() Podstawy programowania II - Dziedziczenie
Dziedziczenie od kilku klas • Klasa może dziedziczyć właściwości kilku klas,np. klasa Kwadrat mogłaby dziedziczyć właściwości klasy Prostokąt i klasy Romb • Składnia:class Potomna : [tryb] Bazowa1, [tryb] Bazowa2 [itd.]{ // deklaracje składników klasy potomnej}; • Utworzenie klasy dziedziczącej od kilku klas może być wartościowe nawet gdy sama klasa nie deklaruje własnych składników. Skupia ona wtedy tylko cechy klas bazowych (np. Kwadrat) Podstawy programowania II - Dziedziczenie
Dostęp do dziedziczonych składników • Dziedziczenie wymaga podania trybu dziedziczenia(private, protected lub public) • Dostęp do dziedziczonych składników zależy trybu dziedziczenia oraz od ich trybów dostępu zdefiniowanych w klasie bazowej: • Dla trybu dziedziczenia public, tryby dostępu: • private - brak dostępu w klasie potomnej, jedyna droga to wykorzystanie odziedziczonych funkcji (ale nie prywatnych!) • protected - funkcje składowe klasy potomnej mają dostęp, z zewnątrz - brak (tak, jakby były prywatne) • public - dostęp zarówno w klasie, jak i z zewnątrz • Dziedziczenie w trybie protected powoduje zablokowanie dostępu z zewnątrz do wszystkich składników, a tryb private - blokuje je również dla ewentualnych klas potomnych Podstawy programowania II - Dziedziczenie
Dostęp w trybie public class Potomna : public Bazowa {public:float dodatek;Potomna() //konstruktor{ prywatny=0; // private chroniony=0; //protect. publiczny=0; // public dodatek=0;} }; class Bazowa {int prywatny;protected:int chroniony;public:int publiczny; }; void main() { Potomna obiekt; obiekt.publiczny=0; obiekt.chroniony=0; obiekt.dodatek=0;} Podstawy programowania II - Dziedziczenie
Dostęp w trybie protected class Potomna : protected Bazowa {public:float dodatek;Potomna(){ prywatny=0; // private chroniony=0;// protected publiczny=0;// protected!! dodatek=0;} }; class Bazowa {int prywatny;protected:int chroniony;public:int publiczny; }; void main() { Potomna obiekt; obiekt.publiczny=0; // teraz już chroniony! obiekt.chroniony=0; obiekt.dodatek=0;} class Wnuk : public Potomna{ public: Wnuk() { chroniony=1; publiczny=1; } }; Podstawy programowania II - Dziedziczenie
Dostęp w trybie private class Potomna : private Bazowa {public:float dodatek;Potomna(){ prywatny=0; // private chroniony=0;// private!! publiczny=0;// private!! dodatek=0;} }; class Bazowa {int prywatny;protected:int chroniony;public:int publiczny; }; class Wnuk : public Potomna{ public: Wnuk() { chroniony=1; // teraz już prywatny! publiczny=1; // teraz już prywatny! }}; Przykład: DZIEDZICZENIE2.CPP Podstawy programowania II - Dziedziczenie
Przesłanianie składników klasy bazowej • W klasie potomnej można utworzyć daną lub funkcję o identycznej nazwie jak w klasie bazowej • Składnik klasy bazowej jest wtedy przesłonięty, niedostępny przez swoją nazwę • Dostęp do przesłoniętego składnika umożliwia operator zakresu :: class A { int x; }; class B {int x; wypisz_oba() { cout << "Bazowa: " << A::x << "Potomna: " << x; } }; Przykład: WEKTORY.CPP Podstawy programowania II - Dziedziczenie
Przesłanianie funkcji klasy bazowej • Znacznie częściej przesłania się funkcje niż dane, ponieważ umożliwia to zmianę zachowania się obiektów. • Jest to przydatne podczas korzystania z gotowych klas,można podmienić działanie wybranej funkcji class A{ public: int x; void wypisz() { cout << x; } // ta funkcja nam się nie podoba}; class nowaA : public A { public:void wypisz() { cout << "x= " << x << endl; }// podmiana}; Podstawy programowania II - Dziedziczenie
Dziedziczeniekonstruktory i destruktor • Konstruktorów ani destruktorów się nie dziedziczy • Konstruktor klasy potomnej musi wywołać konstruktory klas bazowych (lista inicjalizacyjna),chyba że klasy bazowe zdefiniowały konstruktory domniemane • Kolejność wykonywania konstruktorów: • Konstruktory klas bazowych • Konstruktory obiektów - składników klasy • Konstruktor klasy potomnej Przykłady: WEKTORY.CPP, FIGURY.CPP Podstawy programowania II - Dziedziczenie
Co można przypisać do obiektu? // wyrażenie tego samego typu, np. obiekt tej samej klasyKlasa obiekt1, obiekt2;obiekt1= obiekt2; // obiekt chwilowy utworzony za pomocą konstruktoraobiekt1= KonstruktorKlasy(pararmetry);// obiekt klasy potomnej, z dowolnego pokoleniaKlasaPotomna pot;obiekt1=pot;// skopiowane zostaną tylko odziedziczone dane // pot=obiekt1; // odwrotnie nie można przypisać // wywołanie funkcji zwracającej obiekt tej lub potomnej klasyobiekt1=funkcja(parametry); Podstawy programowania II - Dziedziczenie
Co można przypisać do wskaźnika na obiekt? // wyrażenie tego samego typu, np. obiekt tej samej klasyKlasa obiekt1, obiekt2;Klasa *wsk1, *wsk2;// pobrazny adres obiektu tej samej klasywsk1 = &obiekt1; // inny wskaźnik do tej samej klasywsk2=wsk1; // wskaźnik na obiekt klasy potomnejKlasaPotomna potomek;KlasaPotomna *pwsk=&potomek;wsk1=&potomek;wsk2=pwsk;// pwsk=wsk1 // odwrotnie się nie da! Podstawy programowania II - Dziedziczenie
Polimorfizm • Mechanizm ten jest ściśle związany z dziedziczeniem i działa w sytuacji, gdy: • W klasie bazowej zdefiniowano pewną funkcję jako wirtualną (virtual) • Klasy potomne definiują funkcję o identycznym nagłówku jak w klasie bazowej (teoretycznie powinna zostać przesłonięta) • W programie korzystamy ze wskaźnika na klasę bazową do pokazywania na obiekty zarówno klasy bazowej jak i klas potomnych • W momencie wywołania funkcji wirtualnej dla obiektu pokazywanego przez ten wskaźnik, zostanie automatycznie wybrana odpowiednia wersja funkcji wirtualnej! Podstawy programowania II - Dziedziczenie
Przykład polimorfizmu class Parent{ public:virtual void Hello() // funkcja wirtualna { printf("Parent!\n"); }};class Child : public Parent // dziedziczenie public: void Hello() // tu virtual moze byc ale nie musi { printf("Child!\n"); }};Parent par; // obiekt klasy bazowejChild ch; // obiekt klasy potomnej Parent *parent_wsk; // wskaźnik na klasę bazowąparent_wsk=∥ // adres obiektu bazowegoparent_wsk->Hello(); // "Parent" (nic dziwnego)parent_wsk->&ch; // adres obiektu potomnego parent_wsk->Hello(); // "Child" !!!! Podstawy programowania II - Dziedziczenie
Funkcja czysto wirtualna iklasa abstrakcyjna • Czasem klasę tworzy się wyłącznie po to aby stanowiła bazę dla kilku klas potomnych, np. pewna funkcja tej klasy ma sens tylko dla klas potomnych, a nie ma sensu dla klasy bazowej • Funkcję taką można utworzyć jako czysto wirtualną, tzn. niezdefiniowaną dla klasy bazowej, ale za to konieczną do zdefiniowania w klasach potomnych • Klasę, która zawiera choćby jedną taką funkcję nazywa się klasą abstrakcyjną, a tworzenie obiektów tej klasy jest zabronione • Przykład deklaracji:class Abstrakcyjna{ public: virtual void CzystoWirtualna()=0;}; Podstawy programowania II - Dziedziczenie