1 / 51

Dziedziczenie

Dziedziczenie. class osoba { char * imie, * nazwisko; public: void wypisz_imie(); void wypisz_nazwisko(); void wypisz_wszystko(); }. class dorosly { char * imie, * nazwisko, * nr_dowodu; public: void wypisz_imie(); void wypisz_nazwisko();

harlan-paul
Download Presentation

Dziedziczenie

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. Dziedziczenie

  2. class osoba { char * imie, * nazwisko; public: void wypisz_imie(); void wypisz_nazwisko(); void wypisz_wszystko(); } class dorosly { char * imie, * nazwisko, * nr_dowodu; public: void wypisz_imie(); void wypisz_nazwisko(); void wypisz_numer(); void wypisz_wszystko(); } Po co nam dziedziczenie?

  3. class osoba { char * imie, * nazwisko; public: void wypisz_imie(); void wypisz_nazwisko(); void wypisz_wszystko(); } class dorosly: public osoba { char * nr_dowodu; public: void wypisz_numer(); void wypisz wszystko(); } Po co nam dziedziczenie?

  4. Dziedziczenie • Wyraża związki hierarchiczne między klasami • Rozbudowywanie istniejących klas, bez ich modyfikowania lub rekompilacji • Wykorzystanie już gotowego kodu (definiujemy tylko to , co dodane lub zmienione)

  5. Dziedziczenie • Klasa bazowa osoba • Klasa pochodna dorosly każdy dorosły jest osobą dorosły jest przypadkiem szczególnym osoby

  6. Klasa pochodna • dorosły zawiera zmienne i metody: char * imie, * nazwisko — odziedziczone, niedostępne dla kl. dorosly char *nr_dowodu — prywatne dla dorosly wypisz_imie(), wypisz_nazwisko() — publiczne, odziedziczone z osoba osoba::wypisz_wszystko() — publiczne, odziedziczone i przysłonięte, dostępne po kwalifikacji op. zakresu

  7. Klasa pochodna • zawiera wszystkie pola bazowej • dziedziczy wszystkie metody, może je przedefiniowywać • do dostępnych lecz przysłoniętych nazw z zakresu klasy bazowej odwołujemy się za pomocą operatora zakresu

  8. Klasa pochodna osoba.o; dorosly s; o.wypisz_imie(); o.wypisz_nazwisko(); o.wypisz_wszystko(); s.wypisz_imie(); // z osoba s.wypisz_nazwisko(); // z osoba s.wypisz_numer(); // z dorosly s.wypisz_wszystko(); // z dorosly s.osoba::wypisz_wszystko(); // z osoba

  9. Dostęp do pól kl. bazowej class pochodna : public bazowa; class pochodna : protected bazowa; class pochodna : private bazowa; class pochodna : bazowa; // : private

  10. sekcja w kl. bazowej Dostęp do pól kl. bazowej

  11. Dostęp do pól kl. bazowej class a { public: int f(int); }; class b:private a//można „osłabić” ograniczenie dostępu { public: a::f; // teraz a::f jest dziedziczone publicznie };

  12. class baza { public: int ba_pub, i; protected: int ba_prot; private: int ba_priv; }; class prot: protected baza { public: int i; void metoda(); protected: int prot_prot; friend void friend_prot(); }; Dostęp do pól kl. bazowej

  13. void prot::metoda() { int i; i=baza::i; i=i; i=prot::i; i=ba_pub; i=baza::ba_pub; i=prot::ba_pub; i=ba_prot; i=baza::ba_prot; i=prot::ba_prot; // i=ba_priv; // i=baza::ba_priv; // i=prot::ba_priv; i=prot_prot; i=prot::prot_prot; } Dostęp do pól kl. bazowej

  14. void not_a_friend() { baza ba; prot pr; int i; i=ba.i; i=ba.ba_pub; // i=ba.ba_prot; // i=ba.ba_priv; // i=pr.baza::i; !!!!! i=pr.i; i=pr.prot::i; // i=pr.ba_pub; // i=pr.baza::ba_pub; // i=pr.prot::ba_pub; // i=pr.ba_prot; // i=pr.baza::ba_prot; // i=pr.prot::ba_prot; // i=pr.ba_priv; // i=pr.baza::ba_priv; // i=pr.prot::ba_priv; // i=pr.prot_prot; // i=pr.prot::prot_prot; } Dostęp do pól kl. bazowej

  15. void friend_prot(void) { baza ba; prot pr; int i; i=ba.i; i=ba.ba_pub; // i=ba.ba_prot; // i=ba.ba_priv; i=pr.baza::i;// !!!!! i=pr.i; i=pr.prot::i; i=pr.ba_pub; i=pr.baza::ba_pub; i=pr.prot::ba_pub; i=pr.ba_prot; i=pr.baza::ba_prot; i=pr.prot::ba_prot; // i=pr.ba_priv; // i=pr.baza::ba_priv; // i=pr.prot::ba_priv; i=pr.prot_prot; i=pr.prot::prot_prot; } Dostęp do pól kl. bazowej

  16. Konstruktor i destruktor dla klasy potomnej • Konstruktorów się nie dziedziczy, ale • Kolejność konstrukcji obiektu klasy: • wirtualne klasy bazowe • bezpośrednie klasy bazowe • obiektowe zmienne klasowe • dana klasa • Destruktory - odwrotnie

  17. Konstruktor i destruktor dla klasy potomnej – lista inicjalizacyjna • Opisuje sposób inicjalizacji zmiennych klasowych zadeklarowanych w klasie(a nie odziedziczonych). • Opisuje sposób wywołania konstruktorów przodków wirtualnych oraz bezpośrednich.

  18. class osoba { protected: char * imie, * nazwisko; char * aloc_string(const char * s); public: osoba(const char * im, const char * naz) :imie(aloc_string(im)), nazwisko(aloc_string(naz)) { } ~osoba() { delete [] imie; delete [] nazwisko; } void wypisz_imie(); void wypisz_nazwisko(); void wypisz_wszystko(); } Przykład

  19. char * osoba::aloc_string(const char * s) { char * cp=new char[strlen(s) + 1]; strcpy(cp, s); return cp; } void osoba::wypisz_imie() { cout << imie << " "; } void osoba::wypisz_nazwisko() { cout << nazwisko << " "; } void osoba::wypisz_wszystko() { wypisz_imie(); wypisz_nazwisko(); } Przykład

  20. class dorosly:public osoba { protected: char * nr_dowodu; public: dorosly(const char * imie, const char * nazwisko, const char * dowod) :osoba(imie, nazwisko), nr_dowodu(aloc_string(dowod)) { }; ~dorosly() { delete [] nr_dowodu; }; void wypisz_numer(); void wypisz_wszystko(); }; Przykład - konstruktor klasy pochodnej

  21. Przykład void dorosly::wypisz_numer() { cout << "dowod: " << nr_dowodu << " "; } void dorosly::wypisz_wszystko() { osoba::wypisz_wszystko(); wypisz_numer(); }

  22. Przykład – wiele kl. pochodnych osoba dorosly dziecko

  23. class dziecko:public osoba { protected: osoba * mama, * tata; public: dziecko(const char * imie, const char * nazwisko, osoba * mama, osoba * tata) :osoba(imie, nazwisko), mama(mama), tata(tata) { }; // ~dziecko() //wystarczy wygenerowany automatycznie – dlaczego? void wypisz_wszystko(); };

  24. Przykład void dziecko::wypisz_wszystko() { osoba::wypisz_wszystko(); cout << "mama: " ; mama->wypisz_wszystko(); cout << "tata: " ; tata->wypisz_wszystko(); }

  25. Przykład – kl. bazowe i pochodne osoba dorosly dziecko posel

  26. class posel:public dorosly { protected: char * nr_immunitetu; public: posel(const char * imie, const char * nazwisko, const char * dowod, const char * immunitet) :dorosly(imie, nazwisko, dowod), nr_immunitetu(aloc_string(immunitet)) { // klasę osoba możemy skonstruować tylko pośrednio }; ~posel() { delete [] nr_immunitetu; } void wypisz_wszystko(); };

  27. Przykład void posel::wypisz_wszystko() { dorosly::wypisz_wszystko(); cout << "immunitet : " << nr_immunitetu; }

  28. Struktury • Struktury w C++ to też klasy struct A { coś tam } odpowiada class A {public: coś tam }

  29. struct xy { int x,y; xy(int x, int y) : x(x), y(y) {} }; //xy xy1={10,20}; — źle xy xy1(10,10); //ok Struktury i klasy • Inicjatorem klamrowym można inicjalizować wyłączniepola klasy w której wszystkie dane są publiczne i nie zdefiniowano konstruktora. struct s_xy { int x,y; }; s_xy sxy={10,20}; // ok. //s_xy sxy1(10,10) - źle

  30. Unie • W C++ unia jest klasą, ale • nie może zawierać obiektów z zdefiniowanymi konstruktorami bądź destruktorami • nie wolno ograniczać dostępu do pól - wszystkie pola muszą być publiczne

  31. W klasach zadeklarować zmienne: punkt: int kolor; xy polozenie okrag:public punkt int promien odcinek:public punkt xy rozmiar; prostokąt:public odcinek Przykład – kl. bazowe i pochodne punkt okrąg odcinek prostokąt • Zadeklarować klasy, konstruktory, przesuń, +=

  32. Przykład – kl. bazowe i pochodne struct xy { int x,y; xy(int x, int y): x(x), y(y) { } };

  33. class punkt { int kolor; xy polozenie; public: punkt(int kolor, xy poz):kolor(kolor), polozenie(poz) { } void przesun(int dx, int dy) { polozenie.x+=dx; polozenie.y+=dy; } punkt & operator+=(int d) { return *this; } };

  34. class okrag:public punkt { int promien; public: okrag(int kolor, xy poz, int promien) :punkt(kolor, poz), promien(promien) { } okrag & operator+=(int d) { (promien*=100+d)/=100; return *this; } };

  35. class odcinek:public punkt { xy rozmiar; public: odcinek(int kolor, xy poz, int p2_x, int p2_y) :punkt(kolor, poz), rozmiar(p2_x, p2_y) { } odcinek & operator+=(int d) { (rozmiar.x*=100+d)/=100; (rozmiar.y*=100+d)/=100; return *this; } };

  36. class prostokat:public odcinek { public: prostokat(int kolor, xy poz, int p2_x, int p2_y) :odcinek(kolor, poz, p2_x, p2_y) { } prostokat & operator+=(int d) { odcinek::operator+=(d); return *this; } };

  37. Jak się zmieni hierarchia klas? xy polozenie int x,y punkt :public xy int kolor; okrag:public punkt int promien odcinek:public punkt xy rozmiar; prostokąt:public odcinek Przykład – kl. bazowe i pochodne xy punkt okrąg odcinek prostokąt

  38. class punkt:public xy { int kolor; // xy polozenie public: punkt(int kolor, xy poz) :kolor(kolor), xy(poz) { } void przesun(int dx, int dy) { x+=dx;// publiczne w przodku y+=dy; } punkt & operator+=(int d) { return *this; } };

  39. Konwersja potomna → bazowa • Automatyczna (niejawna) konwersja wskaźnika do klasy potomnej na wskaźnik do bazowej jest dozwolona przy dziedziczeniu publicznym • rationale • Przykład osoba o(…); dorosly d(…); dziecko x(„Jaś”, „Kowalski”, &o, &d); x.wypisz_wszystko() // nie wypisze dowodu d

  40. Konwersja potomna → bazowa • Automatyczna (niejawna) konwersja wskaźnika do klasy potomnej na wskaźnik do bazowej jest dozwolona przy dziedziczeniu publicznym • uwaga: destrukcja przez wskaźnik po konwersji osoba *o=new dorosly("aa", "bb", "cc"); delete o; // nie zwolni nr_dowodu • rozwiązanie: destruktor wirtualny.

  41. Konwersja potomna → bazowa • Skojarzenie referencji do klasy potomnej z obiektem klasy bazowej jest dozwolone przy dziedziczeniu publicznym • uwagi (konwersje wskaźników oraz referencji): • te konwersje są przechodnie • dozwolone wyłącznie dla dziedziczenia publicznego (aby uniemożliwić obejście ograniczenia dostępu do pól odziedziczonych jako private/protected)

  42. class A {}; class B: public A {}; class C: private A {}; int fa(A a) {}; int fb(B b) {}; ------------------------------ A a; B b; C c; fa(a); // konstruktor kopiujący A fa(b); // jak wyżej // fa(c); // błąd // fb(a); fb(b); // fb(c); A *pa0=&a; A *pa1=&b; // A *pa2=&c; // B *pb=&a; // C *pc=&a; A &ra0=a; A &ra1=b; // A &ra2=c; // B &rb=a; // C &rc=a; Konwersja potomna → bazowa

  43. class A {}; class B: public A {}; class C: private A {}; class D: public B{}; int fa(A a) {}; --------------------------- D d; fa(d); // przechodnie Konwersja potomna → bazowa

  44. Konstruktor kopiujący klasy pochodnej • to jest konstruktor, a zatem • obowiązuje koleność konstrukcji obiektów: zawsze wywołają się konstruktory klas bazowych. • można użyć listy inicjalizacyjnej by określić sposób wywołania konstruktora klasy bazowej • Przypomnienie: konstruowane będą również obiekty zawarte w danym.

  45. Konstruktor kopiujący klasy pochodnej class potomek:public baza { ... }; potomek::potomek(const potomek & p) :baza(p)// niejawna konwersja do kl. bazowej { ... };

  46. Konstruktor kopiujący klasy pochodnej • podobnie jak konstruktor domyślny i destruktor, konstruktor kopiującymoże być generowany automatycznie • jeżeli w klasie potomnej nie zdefiniujemy go to zostanie wygenerowany • przed nim wywoła się konstruktor kopiujący klasy bazowej (a nie bezparametrowy, czyli odwrotnie niż w przypadku konstr. kop. nie-generowanego) • musi być dostępny k. kopiujący. klasy bazowej (być i być publiczny)

  47. Operator przypisania klasy pochodnej • Wygenerowany automatycznie operator przypisania kopiuje składowe danej klasy pole po polu • najpierw klasa bazowa kopiowana jest operatorem przypisania, potem obecna. • nie zostanie wygenerowanyjeżeli klasa zawiera pola stałe albo referencje(w klasie albo przodkach), ani jeżeli w klasie bazowej lub obiekcie zawartym op.= był prywatny. • prawdopodobnie nie sprawdzi się dla pól wskaźnikowych • jeżeli napiszemy własny operator to odziedziczony operator nie wywoła się sam, trzeba to zrobić jawnie.

  48. Operator przypisania klasy pochodnej class potomek:public baza{ ... }; potomek & potomek::operator=(const potomek & p) { if (this == &p) return *this; this->baza::operator=(p); // alternatywy: baza *pb=this; (*pb)=p; // baza *pb=this; pb->operator=(p); // baza &rb=*this; rb=p; // przypisanie dla własnej klasy return *this; // zwrócenie wartości };

  49. class dorosly: public osoba { char * nr_dowodu; … } Przykład • Konstruktory kopiujące i operatory przypisania dla klas osoba i dorosły class osoba { char * imie, * nazwisko; … }

  50. Przykład osoba::osoba(const osoba &o) :imie(aloc_string(o.imie)),nazwisko(aloc_string(o.nazwisko)) {} osoba & osoba::operator=(const osoba &o) { if (this == &o) return *this; delete [] imie; imie=aloc_string(o.imie); delete [] nazwisko; nazwisko=aloc_string(o.nazwisko); return *this; }

More Related