Programowanie obiektowe PO PO - LAB 2 Wojciech Pieprzyca
Dziedziczenie w swej istocie polega na definiowaniu nowej klasy przy użyciu klasy, która już wcześniej istniała. Czasami nie ma konieczności definiowania czegoś zupełnie od początku, można posłużyć się dobrze działającą i przetestowaną klasą, która będzie stanowiła podstawę do budowy i rozwoju kolejnej klasy. Klasę z której dziedziczymy jej składowe i metody nazywamy klasą bazową. Klasę, która dziedziczy te elementy nazywamy klasą pochodną. Innymi słowy klasa pochodna dziedziczy składowe i metody po klasie bazowej. A zatem klasa pochodna będzie mogła mieć dostęp do składowych i metod zdefiniowanych w klasie bazowej, czyli nie będzie trzeba ich powtórnie definiować w klasie pochodnej, co już samo w sobie jest zaletą. Dziedziczenie (I) PO
Naszym celem jest określenie następującej hierarchii klas: Dziedziczenie (II) PO Zwierze *nazwa, iloscNog * jedz() * spij() Ssak * futro * pijMleko() * rozmazaj() waleczneSerce * szukaj() * poluj() Ptak * lec() * spiewaj() Pies * rodzajSiersci * rozmnazanie() Orzel
Jak zapisać to w języku C++ ? class nazwaKlasyBazowej { //definicje składowych i metod klasy bazowej }; class nazwaKlasyPochodnej : kwalifikatorDostepu nazwaKlasyBazowej { //definicje składowych i metod klasy pochodnej } Różnica przy definiowaniu klasy pochodnej polega na tym iż w nagłówku po nazwie klasy podajemy listę klas bazowych po których klasa pochodna ma dziedziczyć. Dodatkowo określamy tzw. kwalifikator dostępu, który będzie określał jak mają być dziedziczone składowe public i protected z klas bazowych. Dziedziczenie (III) PO
Jak wykorzystywać kwalifikatory dostępu ? W klasie bazowej istnieją składowe i metody, które mają określony dostęp jako publiczny (public), chroniony (protected) lub prywatny (private). Pozostaje pytaniem otwartym jaki dostęp do tych składowych i metod ma być określony w nowo definiowanej klasie (klasie pochodnej). Jednej rzeczy możemy być pewni. Wszystkie elementy klasy bazowej z dostępem private zostaną odziedziczone jako prywatne tzn. dostęp do nich będzie taki jakbyśmy zdefiniowali je w sekcji private klasy pochodnej. Natomiast elementy klasy bazowej z dostępem protected lub public mogą być dziedziczone na różne sposoby. I w tym celu wykorzystuje się kwalifikator dostępu. Możemy zatem określić iż składowe i metody klasy bazowej z dostępem public i protected będą w klasie pochodnej miały określone dostęp jako: public, lub protected, lub private. Dziedziczenie (IV) PO
Prosty przykład class podstawowa { public: void wolaj(); protected: char tab[20]; private: float oc; }; class rozszerzona : public podstawowa { }; Klasa rozszerzona będzie dziedziczyła składową oc jako private (ponieważ wszystkie elementy private dziedziczone są zawsze jako prywatne). Kwalifikator dostępu public określa natomiast iż metoda wolaj() i składowa tab będą odziedziczone jako public. Dziedziczenie (V) PO
Definicja struktury klas z diagramu class Zwierze { private: char nazwa[20]; int iloscNog; public: Zwierze(char *_nazwa, int _iloscNog); void jedz(); void spij(); }; Zwierze::Zwierze(char *_nazwa, int _iloscNog) { strcpy(nazwa,_nazwa); iloscNog = _iloscNog; cout << "Tworzymy obiekt o nazwie " << nazwa << endl; } Dziedziczenie (VI) PO
void Zwierze::jedz() { cout << "Zwierze je" << endl; } void Zwierze::spij() { cout << "Zwierze spi" << endl; } Klasa Zwierze jest klasą bazową dla wszystkich rodzin zwierząt (w naszym przypadku ograniczyliśmy się do definicji rodziny Ssaków i Ptaków). Przechowujemy informacje o nazwie zwierzęcia i ilości nóg które ono posiada. Dodatkowo każde zwierze może jeść i spać. Składowe są prywatne, a metody publiczne. Dziedziczenie (VII) PO
class Ptak : public Zwierze { public: Ptak(char *nazwa, int nog); void lec(); void spiewaj(); }; Ptak::Ptak(char *nazwa, int nog) : Zwierze(nazwa,nog) { cout << "Tworzymy obiek typu ptak" << endl; } Dziedziczenie (VIII) PO
void Ptak::lec() { cout << "Ptak sobie leci" << endl; } void Ptak::spiewaj() { cout << "Ptak spiewa" << endl; } Ptak jest klasą pochodną względem klasy Zwierze. Dziedziczy więc wszystkie składowe i metody z klasy Zwierz (z dostępem public bo taki zdefiniowaliśmy kwalifikator dostępu). Dodatkowo dodane są metody pozwalające ptakowi latać i śpiewać. Składowe z klasy Zwierz (nazwa, nog) są nadal prywatne. Natomiast wszystkie metody zarówno odziedziczone jak i zdefiniowane jawnie są publiczne. W konstruktorze dodatkowo wywołujemy konstruktor klasy bazowej i podajemy mu argumenty przekazane do konstruktora klasy pochodnej. Dziedziczenie (IX) PO
class Ssak : public Zwierze { private: bool futro; public: Ssak(char *nazwa, int nog); void pijMleko(); protected: void rozmnazaj(); }; Ssak::Ssak(char *nazwa, int nog) : Zwierze(nazwa,nog) { cout << "Tworzymy obiekt typu ssak" << endl; } Dziedziczenie (X) PO
void Ssak::pijMleko() { cout << "Ssak pije mleko matki" << endl; } void Ssak::rozmnazaj() { cout << "Ssak sie rozmnaza" << endl; } Ssak jest klasą pochodną względem klasy Zwierze. Dziedziczy wszystkie składowe i metody z klasy Zwierz (z dostępem public bo taki zdefiniowaliśmy kwalifikator dostępu). Dodatkowo dodane są metody pozwalające ssakowi pić mleko oraz rozmnażać się. Składowe z klasy Zwierz (nazwa, nog) są nadal prywatne. Metody odziedziczone i metoda pijMleko są publiczne. Natomiast metoda rozmnazaj jest chroniona (protected). Można ją zatem wywołać tylko z wnętrza klasy Ssak lub jej klas pochodnych (będą to klasy Pies i Pies2). W konstruktorze dodatkowo wywołujemy konstruktor klasy bazowej i podajemy mu argumenty przekazane do konstruktora klasy pochodnej. Dziedziczenie (XI) PO
class WaleczneSerce { public: void szukaj(); void poluj(); }; void WaleczneSerce::szukaj() { cout << "Waleczne serce szuka" << endl; } void WaleczneSerce::poluj() { cout << "Waleczne serce poluje" << endl; } Dziedziczenie (XII) PO
class Pies : public Ssak, public WaleczneSerce { private: char rodzajSiersci[20]; public: Pies(char *nazwa, int nog); void rozmnazanie() { rozmnazaj(); } }; Pies::Pies(char *nazwa, int nog) : Ssak(nazwa,nog) { cout << "Tworzymy obiekt typu pies" << endl; } Dziedziczenie (XIII) PO
class Pies2 : public Ssak, protected WaleczneSerce { private: char rodzajSiersci[20]; public: Pies2(char *nazwa, int nog); void rozmnazanie() { rozmnazaj(); } }; Pies2::Pies2(char *nazwa, int nog) : Ssak(nazwa,nog) { cout << "Tworzymy obiekt typu pies2" << endl; } Dziedziczenie (XIV) PO
class Orzel : public Ptak, public WaleczneSerce { public: Orzel(char *nazwa, int nog); }; Orzel::Orzel(char *nazwa, int nog) : Ptak(nazwa,nog) { cout << "Tworzymy obiekt typu orzel"<<endl; } W przypadku klas Pies, Pies2 oraz Orzel mamy do czynienia z dziedziczeniem wielobazowym. To znaczy dziedziczymy po kilku klasach (w tym przypadku po dwóch, Ssak i WaleczneSerce lub Ptak i WaleczneSerce). Dodatkowo w klasie Pies możemy wywołać metodą chronioną rozmnazaj() klasy Ssak. Robimy to wewnątrz metody rozmnazanie(), która jest publiczna. W ten sposób niejako pośrednio uzyskujemy możliwość wywołania metody rozmnazaj(). Dziedziczenie (XV) PO
int main(int argc, char *argv[]) { Zwierze zwierz("swidrzyk lamliwy",1); zwierz.jedz(); zwierz.spij(); cout << "***" << endl; getch(); Ptak ptak("sikorka",2); ptak.jedz();//metody jedz i spij pochodza z klasy Zwierze ptak.spij(); ptak.lec();//metody lec i spiewaj z klasy Ptak ptak.spiewaj(); cout << "***" << endl; getch(); Dziedziczenie (XVI) PO
Ssak ssak("niedzwiedz",4); ssak.jedz();//metody jedz i spij z klasy Zwierze ssak.spij(); ssak.pijMleko();//metoda pijMleko z klasy Ssak //ssak.rozmnazaj(); //nie da sie poniewaz ta metoda jest protected cout << "***" << endl; getch(); Pies pies("owczarek",4); pies.jedz();//metody jedz i spij z klasy Zwierze pies.spij(); pies.pijMleko();//metoda pijMleko z klasy Ssak pies.rozmnazanie();//metoda rozmnazanie z klasy Pies pies.szukaj();//metody szukaj i poluj z klasy WaleczneSerce pies.poluj(); cout << "***" << endl; getch(); Dziedziczenie (XVII) PO
Pies2 pies2("jamnik",4); //pies2.szukaj(); //nie da sie poniewaz te metody zostaly odziedziczone //pies2.poluj(); //jako protected cout << "Ten pies nie ma walecznego serca"<<endl; cout << "***" << endl; getch(); Orzel orzel("bielik",2); orzel.jedz();//metody jedz i spij z klasy Zwierze orzel.spij(); orzel.lec();//metody lec i spiewaj z klasy Ptak orzel.spiewaj(); orzel.szukaj();//metody szukaj i poluj z klasy WaleczneSerce orzel.poluj(); cout << "***" << endl; getch(); return 0; } Dziedziczenie (XVIII) PO