210 likes | 407 Views
Dziedziczenie wielobazowe. Dziedziczenie wielobazowe. dana klasa może mieć kilka bezpośrednich klas bazowych : kolor położenie punkt dziedziczenie wielobazowe to sposób , w jaki programista opisuje obiekty które łączą cechy różnych klas. Dziedziczenie wielobazowe.
E N D
Dziedziczenie wielobazowe • dana klasa może mieć kilka bezpośrednich klas bazowych: kolorpołożenie punkt • dziedziczenie wielobazowe to sposób, w jaki programista opisuje obiekty które łączą cechy różnych klas.
Dziedziczenie wielobazowe • dana klasa może mieć kilka bezpośrednich klas bazowych: kolorpołożenie punkt class kolor {}; class położenie {}; class punkt: public kolor, public położenie { ... };
Deklaracja klasy pochodnej class punkt: public kolor, public położenie { ... }; • domyślnie dziedziczymy prywatnie, jeżeli chcemy publicznie to zadeklarujmy to jawnie dla każdej z klas bazowych, która ma być przodkiem publicznym • dwukropek w deklaracji występuje tylko raz, potem przecinki • wszystkie klasy bazowe muszą być w całości zdefiniowane • nie wystarczy definicja nazwy klasy bazowej (class C) • w ten sposób wykluczamy zapętlenie w dziedziczeniu – klasa nie może być własnym przodkiem.
Konstruktory klas bazowych class punkt: public kolor, public położenie { ... }; • konstruktory klas bazowych wywoływane są w kolejności takiej, w jakiej zadeklarowano klasy bazowe w deklaracji danej klasy • kolor() • położenie()
Niejednoznaczności • Występują gdy takie same nazwy pól lub metod odziedziczone są po więcej niż jednej bezpośredniej klasie bazowej. class kolor {public: int k; char *nazwa}; class położenie { public: int k; int j }; class punkt: public kolor, public położenie { ... }; punkt zawiera pola: kolor::kpołożenie::k kolor::nazwapołożenie::j
Niejednoznaczności punkt zawiera pola: kolor::kpołożenie::k kolor::nazwapołożenie::j • odwołania w zakresie klasy punkt: punkt::nazwa; // OK punkt::j; // OK // punkt::k — błąd • taki błąd wystąpi również gdy jest tylko jedna dostępna nazwa (gdy np. pozostałe są prywatnymi składowymi klas) • najpierw jest sprawdzana jednoznaczność, potem dostępność. • żeby uniknąć niejednoznaczności należy podać, operatorem zakresu, przodka od którego nazwa pochodzi
Niejednoznaczności class kj {public: int k,j}; class odcinek: public punkt, public polozenie {}; • klasa odcinek zawiera pola: punkt::kolor::kkj::k punkt::kolor::nazwakj::j punkt::położenie::k punkt::położenie::j • odwołując się do nazwy, trzeba podać zakres, w którym jest jednoznaczna: odcinek::nazwa→ odcinek::punkt::kolor::nazwa położenie::j → odcinek::punkt::położenie::j punkt::j → odcinek::punkt::położenie::j położenie::k→ odcinek::punkt::położenie::k
Niejednoznaczności • Aby zlikwidować niejednoznaczność nazwy można zdefiniować akcesor, którego nazwa przykryje nazwę niejednoznaczną. • np. dla klasy punkt: int & punkt::k(){ return kolor::k; } • użycie: punkt p; p.k()=7; • wewnątrz metod klasy punkt i pochodnych punkt::k() będzie się zachowywać jak pukt::kolor::k • niedoskonałe – bo zmienną zastępujemy metodą, • skuteczne – bo kompilator zoptymalizuje kod
Wielokrotne wystąpienia tej samej klasy bazowej • każdy z bezpośrednich przodków musi występować pojedynczo. • nie wolno: class odcinek: kolor, położenie, położenie {}; • bezpośredniprzodek nie może być równocześnie niebezpośrednim przodkiem. • nie wolno: class odc_2: punkt, położenie {}; • Wniosek: jeżeli potrzebujemy kilku egzemplarzy danej klasy to: • możemy je zawrzeć w klasie, a nie odziedziczyć • możemy je odziedziczyć kilkakrotnie, lecz każdorazowo jako przodka niebezpośredniego
Wielokrotne wystąpienia tej samej klasy bazowej oknookno o_z ramkąo_z_menu o_z_ramka_i_menu class okno{}; class o_z_ramka:public okno{}; class o_z_menu:public okno {}; class o_z_ramka_i_menu:public o_z_ramka, public o_z_menu{};
Wirtualne klasy bazowe okno o_z ramkąo_z_menu o_z_ramka_i_menu
we wszystkich klasach pochodnych dla których chcemy żeby w razie dziedziczenia po kilku z nich ich bezpośrednia klasa bazowa wystąpiła tylko raz należy tę klasę bazową zadeklarować ze słowem kluczowym virtual wystarczy żeby bezpośredni potomek dziedziczył wirtualnie – o_z_ramka_i_menu już nie musi. Wirtualne klasy bazowe - deklarowanie okno o_z ramkąo_z_menu o_z_ramka_i_menu class okno{}; class o_z_ramka:public virtual okno{}; class o_z_menu:public virtual okno {}; class o_z_ramka_i_menu:public o_z_ramka, public o_z_menu{};
Ograniczenia dostępu do odziedziczonych pól • jeżeli pola wirtualnej klasy bazowejsą dostępne przez przynajmniej jedną ze ścieżek wiodących do tej klasy, to można się odwoływać do nich w zakresie klasy potomnej • Oczywiście jeżeli w innej ścieżce jest dziedziczona prywatnie to nie można użyć zakresu w którym jest niewidoczna • przykład: class o_z_ramka:privatevirtual okno{}; o_z_ramka_i_menu::o;// ok., odpowiednik ponizszego o_z_ramka_i_menu::o_z_menu::o; //ok. // o_z_ramka_i_menu::o_z_ramka::o – tutaj prywatne
bezpośredni przodek wirtualnymoże jednocześnie być przodkiem niebezpośrednim – nie ma niejednoznaczności Ograniczenia dostępu do odziedziczonych pól okno o_z ramkąo_z_menu o_z_ramka_i_menu class okno{}; class o_z_ramka:privatevirtual okno{}; class o_z_menu: privatevirtual okno {}; class o_z_ramka_i_menu :public o_z_ramka, public o_z_menu , public virtual okno{};
Kolejność wywołania konstruktorów • przed wszystkimi innymi wywoływane są konstruktory klas bazowych wirtualnych w kolejności od pierwszego wystąpienia w deklaracji kl. pochodnej. • parametry konstruktora dla klasy bazowej wirtualnej można przekazać w konstruktorach wszystkich (nawet niebezpośrednich) klas pochodnych. • Zastosowanie znajdą te parametry, które opisano w liście inicjalizazacyjnej konstruowanej klasy – np. konstruujemy z_ramka_i_menu to parametry konstrukcji okna z listy okna z ramka zostana zignorowane. • UWAGA: jeżeli nie opisze się wywołania się konstruktora wirtualnej klasy bazowej jawnie to zostanie zastosowany konstruktor domniemany.
Wielokrotne wywoływanie metod klasy bazowej okno o_z ramkąo_z_menu o_z_ramka_i_menu • każda klasa ma metodę rysuj(); • metoda rysuj() danej klasy wywołuje metodę rysuj() przodka; • o_z_ramka_i_menu::rysuj() wywoła metody rysuj() obu przodków; • o_z_ramka_i_menu::rysuj() pośrednio wywoła dwukrotnie okno::rysuj();
Wielokrotne wywoływanie metod klasy bazowej void o_z_ramka::_rysuj() { //tu rysowanie właściwe dla ozramka } void o_z_ramka::rysuj() { okno::_rysuj(); _rysuj(); } void o_z_ramka_i_menu::_rysuj() { //tu rysowanie właściwe dla ozramka } void o_z_ramka_i_menu::rysuj() {okno::_rysuj(); o_z_ramka::_rysuj(); o_z_menu::_rysuj(); _rysuj }
dana klasa może być jednocześnie dziedziczona wirtualnie i nie-wirtualnie UWAGA: bezpośredni przodek nie-wirtualnynie może jednocześnie być przodkiem niebezpośrednim –niejednoznaczność Klasa bazowa wirtualna i nie-wirtualna oknookno o_z ramkąo_z_menu o_z_ramka_i_menu class okno{}; class o_z_ramka: public virtual okno{}; class o_z_menu: public okno {};// okno dziedziczone nie-wirtualnie class o_z_ramka_i_menu// tu nie wolno bez virtual: public okno :public o_z_ramka, public o_z_menu {};