int
Transkrypt
int
Dziedziczenie Bogdan Kreczmer ZPCiR IIAiR PWr pokój 307 budynek C3 [email protected] c 2005–2008 Bogdan Kreczmer? Copyright ? Niniejszy dokument zawiera materiały do wykładu na temat programowania obiektowego. Jest on udostepniony ˛ pod warun- kiem wykorzystania wyłacznie ˛ do własnych prywatnych potrzeb i może on być kopiowany wyłacznie ˛ w całości, razem z niniejsza˛ strona˛ tytułowa. ˛ Uszczegółowianie Figura geometryczna cechy: % Okrag ˛ cechy: • pole • obwód Kwadrat • jest figura˛ cechy: • jest figura˛ geometryczna˛ geometryczna˛ – pole – obwód – pole – obwód • promień c 2005–2008 Bogdan Kreczmer Copyright • długość boku Dziedziczenie 1 Zapis w UML Diagram klas w jezyku ˛ UML odzwierciedlajacy ˛ fakt dziedziczenia ˛ i Kwadrat. klasy Figura Geometryczna przez klasy Okrag c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 2 Zapis w C++ struct Figura Geometryczna { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . double pole; double obwod; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct Okrag: Figura Geometryczna { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . double promien; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct Kwadrat: Figura Geometryczna { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . double dlugosc boku; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 3 Typy dziedziczenia Tryby dziedziczenia: • • • publiczny chroniony prywatny −→ −→ −→ class Klasa Pochodna: public Klasa Bazowa { ... }; class Klasa Pochodna: protected Klasa Bazowa { ... }; class Klasa Pochodna: private Klasa Bazowa { ... }; Klasa Pochodna: . . . Klasa Bazowa −→ class Klasa Pochodna: Klasa Bazowa { ... }; −→ class Klasa Pochodna: private Klasa Bazowa { ... }; struct Klasa Pochodna: Klasa Bazowa { ... }; −→ struct Klasa Pochodna: public Klasa Bazowa { ... }; c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 4 Dziedziczenie w trybie publicznym Tryb dziedziczenia: • publiczny −→ class Klasa Pochodna: public Klasa Bazowa { ... }; Klasa Pochodna: public Klasa Bazowa −→ c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 5 Dziedziczenie w trybie publicznym class KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int PolePryw KBaz; protected : int PoleChro KBaz; public : int PolePubl KBaz; }; //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna: public KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . public : void OdwolanieDoPol( ); }; //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . void KlasaPochodna::OdwolanieDoPol( ) { hhhh h( hhh (((( ( h( hhhh = 0; ( h( hh ((( PolePubl KBaz = PoleChro KBaz =((PolePryw KBaz ((( h (h } Pola i metody prywatne klasy bazowej sa˛ niedostepne ˛ na poziomie metod klasy pochodnej. Dostepne ˛ sa˛ natomiast pola i metody znajdujace ˛ sie˛ w sekcji chronionej i publicznej. Własność ta nie zależy od sposobu dziedziczenia klasy bazowej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 6 Dziedziczenie w trybie publicznym class KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int PolePryw KBaz; protected : int PoleChro KBaz; public : int PolePubl KBaz; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna: public KlasaBazowa { . . . } // . . . . . int main( ) { KlasaBazowa hhh ObBa; int main( ) { KlasaPochodna hh h (( hh ((( ObBa. (PolePryw = 1; ((( hhhKBaz h hhhh ( ( h ((( KBaz = 2; ObBa. (PoleChro ((( hhh h ObBa. PolePubl KBaz = 3; } ObPo; (( h( h(( KBaz = 1; ObPo. ( PolePryw ((( hhh h hhhh ( ( h(( KBaz = 2; ( ObPo. ( PoleChro ((( hhh h ObPo. PolePubl KBaz = 3; } W przypadku dziedziczenia w trybie publicznym pola i metody klasy bazowej, które sa˛ niedostepne ˛ poza ta˛ klasa, ˛ sa˛ również niedostepne ˛ w przypadku obiektu klasy pochodnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 7 Dziedziczenie w trybie chronionym Tryb dziedziczenia: • chroniony −→ class Klasa Pochodna: protected Klasa Bazowa { ... }; Klasa Pochodna: protected Klasa Bazowa −→ c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 8 Dziedziczenie w trybie chronionym class KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int PolePryw KBaz; protected : int PoleChro KBaz; public : int PolePubl KBaz; }; //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna: protected KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . public : void OdwolanieDoPol( ); }; //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . void KlasaPochodna::OdwolanieDoPol( ) { hhhh h( hhh (((( ( h( hhhh = 0; ( h( hh ((( PolePubl KBaz = PoleChro KBaz =((PolePryw KBaz ((( h (h } Dziedziczenie w trybie chronionym nie ogranicza dostepności ˛ pól i metod klasy bazowej na poziomie metod klasy pochodnej. Nie powoduje też, że pola i metody prywatne mogłyby stać sie˛ dostepne ˛ dla klasy pochodnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 9 Dziedziczenie w trybie chronionym class KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int PolePryw KBaz; protected : int PoleChro KBaz; public : int PolePubl KBaz; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna: protected KlasaBazowa { . . . } // . . int main( ) { KlasaBazowa hhh ObBa; int main( ) { KlasaPochodna hhh (( hh ((( ObBa. (PolePryw = 1; ((( hhhKBaz h hhhh ( ( h ((( KBaz = 2; ObBa. (PoleChro ((( hhh h ObBa. PolePubl KBaz = 3; } } ObPo; (( h( h(( KBaz = 1; ObPo. ( PolePryw ((( hhh h hhhh ( ( h(( KBaz = 2; ( ObPo. ( PoleChro ((( hhh h hhh ( ( ( h h( PolePubl = 3; ObPo. ( hh ((((hhKBaz Dziedziczenie w trybie chronionym sprawia, że wszystkie komponenty klasy bazowej staja˛ sie˛ niedostepne ˛ poza klasa˛ pochodna. ˛ c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 10 Dziedziczenie w trybie prywatnym Tryb dziedziczenia: • prywatny −→ class Klasa Pochodna: private Klasa Bazowa { ... }; Klasa Pochodna: private Klasa Bazowa −→ c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 11 Dziedziczenie w trybie prywatnym class KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int PolePryw KBaz; protected : int PoleChro KBaz; public : int PolePubl KBaz; }; //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna: private KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . public : void OdwolanieDoPol( ); }; //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . void KlasaPochodna::OdwolanieDoPol( ) { hhhh h( hhh (((( ( h( hhhh = 0; ( h( hh ((( PolePubl KBaz = PoleChro KBaz =((PolePryw KBaz ((( h (h } Dziedziczenie w trybie prywatnym, podobnie jak dziedziczenie i w trybach publicznym i chronionym, nie ogranicza dostepności ˛ pól i metod klasy bazowej na poziomie metod klasy pochodnej. Nie powoduje też, że pola i metody prywatne mogłyby stać sie˛ dostepne ˛ dla klasy pochodnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 12 Dziedziczenie w trybie prywatnym class KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int PolePryw KBaz; protected : int PoleChro KBaz; public : int PolePubl KBaz; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna: private KlasaBazowa { . . . } // . . . . . int main( ) { KlasaBazowa hhh ObBa; int main( ) { KlasaPochodna hh h (( hh ((( ObBa. (PolePryw = 1; ((( hhhKBaz h hhhh ( ( h ((( KBaz = 2; ObBa. (PoleChro ((( hhh h ObBa. PolePubl KBaz = 3; } } ObPo; (( h( h(( KBaz = 1; ObPo. ( PolePryw ((( hhh h hhhh ( ( h(( KBaz = 2; ( ObPo. ( PoleChro ((( hhh h hhh ( ( ( h h( PolePubl = 3; ObPo. ( hh ((((hhKBaz Dziedziczenie w trybie prywatnym, podobnie jak dziedziczenie w trybie chronionym, sprawia, że wszystkie komponenty klasy bazowej staja˛ sie˛ niedostepne ˛ poza klasa˛ pochodna. ˛ c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 13 Dostepno ˛ ść komponentów class KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int PolePryw KBaz; protected : int PoleChro KBaz; public : int PolePubl KBaz; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna: protected KlasaBazowa { } // . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna Nastepna: public KlasaPochodna { // . . . . . . . . . . . . . . . . . public : void OdwolanieDoPol( ); }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . void KlasaPochodna Nastepna::OdwolanieDoPol( ) { h h h hh h h } ( ( h h hh ( (( h( h ( ( h h h (h ( h h( h ( ( h h hh ( (( PolePubl KBaz = PoleChro KBaz = PolePryw KBaz = 0; hh h ( (( h h ( (( ( ( ( ( Jeżeli klasa bazowa jest dziedziczona w trybie chronionym, to jej komponenty, które dostepne ˛ sa˛ w klasie pochodnej, bed ˛ a˛ dostepne ˛ również w klasie dziedziczacej ˛ klase˛ pochodna, ˛ zaś komponenty prywatne nie bed ˛ a˛ dostepne ˛ (niezależnie do trybu dziedziczenia). c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 14 Dostepno ˛ ść komponentów class KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int PolePryw KBaz; protected : int PoleChro KBaz; public : int PolePubl KBaz; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna: private KlasaBazowa { } // . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna Nastepna: public KlasaPochodna { // . . . . . . . . . . . . . . . . . public : void OdwolanieDoPol( ); }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . void KlasaPochodna Nastepna::OdwolanieDoPol( ) { h h h h h h hh hh hh h ( ( ( ( h h h h h h h ( ( (( (( ( ( } ( ( h h h hh hh hh h h h (( ( ( ( ( ( h h h h h hh h( ( ( (( ( ( ( ( h h h h hh h( h h ( ( ( ( (h h h( h( h h h h h ( ( ( (( ( ( h h h hh hKBaz h h h h h (( (( ( ( (( ( PolePubl KBaz = PoleChro = PolePryw KBaz = 0; hh hh h h h h h hh (( (( (( ( ( ( h h h h h h h (( ( ( ( ( ( ( (( (( ( ( ( Jeżeli klasa bazowa jest dziedziczona w trybie prywatnym, to jej komponenty, które dostepne ˛ sa˛ w klasie pochodnej, nie bed ˛ a˛ dostepne ˛ w klasie dziedziczacej ˛ klase˛ pochodna˛ (niezależnie do trybu dziedziczenia). c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 15 Wielodziedziczenie class KlasaBazowa1 { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaBazowa2 { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna: public KlasaBazowa1, protected KlasaBazowa2 { // . . ... }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W liście dziedziczenia znajdować sie˛ może dowolna ilość klas (górne ograniczenie wynika z możliwości implementacji odpowiednich struktur). Każda z klas bazowych może być dziedziczona w innym trybie. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 16 Wielodziedziczenie class KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ( ( ( ( h h h h hh hh ( ( (( (( h h h h h( ( ( (( ( h h h h h( h( ( ( h h h h h h( ( ( ( (( h h h h h hh hh ( ( (( (( class KlasaPochodna: public KlasaBazowa, protected KlasaBazowa { // . . . . h h hh hh ( ( (( (( h h h h h ( ( ( ( (( (( h h hh h h ( ( ( h h hh h h h ( ( ( ... }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bezpośrednie dziedziczenie tej samej klasy nie jest możliwe. Gdyby było to możliwe prowadziłoby to do niejednoznaczności, gdyż te same nazwy metod i pól znalazłyby sie˛ w tej samej przestrzeni nazw klasy pochodnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 17 Pośrednie dziedziczenie tej samej klasy struct KlasaX { int Pole; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaBazowaA: KlasaX { }; //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaBazowaB: KlasaX { }; //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: KlasaBazowaA, KlasaBazowaB { }; // . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna } ObP; ObP.KlasaBazowaA:: Pole = 1; ObP.KlasaBazowaB:: Pole = 2; h h h hh ( ( h hh (( ( h hh ( (( h( h ( ( h h h (h ( h h( h ( ( ( h h h ( ( ( = 1; ObP.KlasaBazowaA::KlasaX:: h h h ( ( ( h h h Pole ( ( ( Dziedziczenie tej samej klasy może zostać zrealizowane pośrednio. Dzieki ˛ temu możliwe jest jednoznaczne określenie dostepu ˛ do pożadanego ˛ pola. Podanie pełnej nazwy kwalifikowanej w tym przypadku nie jest poprawnym zapisem. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 18 Konstruktory i destruktory - kolejność wywołań class KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . public : KlasaBazowa( ) { cout << ”++Konstruktor: KlasaBazowa” << endl; } ∼ KlasaBazowa( ) { cout << ”--Destruktor: KlasaBazowa” << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class KlasaPochodna: protected KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . public : KlasaPochodna( ) { cout << ”++Konstruktor: KlasaPochodna” << endl; } ∼ KlasaPochodna( ) { cout << ”--Destruktor: KlasaPochodna” << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna ObP; cout << ” Witaj Swiecie !!!” << endl; } Wynik działania: ++Konstruktor: KlasaBazowa ++Konstruktor: KlasaPochodna Witaj Swiecie !!! --Destruktor: KlasaPochodna --Destruktor: KlasaBazowa Zawsze najpierw wywoływane sa˛ konstruktory dla klas dziedziczonych. Wywołanie destruktorów nastepuje ˛ w kolejności odwrotnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 19 Konstruktory i destruktory - kolejność wywołań struct KlasaBazowa1 { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . KlasaBazowa1( ) { cout << ”++Konstruktor: KlasaBazowa1” << endl; } ∼ KlasaBazowa1( ) { cout << ”--Destruktor: KlasaBazowa1” << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaBazowa2 { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . KlasaBazowa2( ) { cout << ”++Konstruktor: KlasaBazowa2” << endl; } ∼ KlasaBazowa2( ) { cout << ”--Destruktor: KlasaBazowa2” << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: protected KlasaBazowa1, public KlasaBazowa2 { // . . . . . . . . KlasaPochodna( ) { cout << ”++Konstruktor: KlasaPochodna” << endl; } ∼ KlasaPochodna( ) { cout << ”--Destruktor: KlasaPochodna” << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna ObP; cout << ” Witaj Swiecie !!!” << endl; } Wynik działania: ++Konstruktor: ++Konstruktor: ++Konstruktor: Witaj Swiecie −−Destruktor: −−Destruktor: −−Destruktor: KlasaBazowa1 KlasaBazowa2 KlasaPochodna !!! KlasaPochodna KlasaBazowa2 KlasaBazowa1 Konstruktory klas dziedziczonych wywoływane sa˛ w kolejności w jakiej wystepuj ˛ a˛ w liście dziedziczenia. Destruktory wywoływane sa˛ w kolejności odwrotnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 20 Konstruktory i destruktory - kolejność wywołań struct Komponent { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Komponent( ) { cout << ”++Konstruktor: Komponent” << endl; } ∼ Komponent( ) { cout << ”--Destruktor: Komponent” << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . KlasaBazowa( ) { cout << ”++Konstruktor: KlasaBazowa” << endl; } ∼ KlasaBazowa( ) { cout << ”--Destruktor: KlasaBazowa” << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: protected KlasaBazowa Komponent Pole; { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . KlasaPochodna( ) { cout << ”++Konstruktor: KlasaPochodna” << endl; } ∼ KlasaPochodna( ) { cout << ”--Destruktor: KlasaPochodna” << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna ObP; cout << ” Witaj Swiecie !!!” << endl; } Wynik działania: ++Konstruktor: ++Konstruktor: ++Konstruktor: Witaj Swiecie −−Destruktor: −−Destruktor: −−Destruktor: KlasaBazowa Komponent KlasaPochodna !!! KlasaPochodna Komponent KlasaBazowa Konstruktory komponentów wywoływane sa˛ po konstruktorach klas dziedziczonych. Destruktory wywoływane sa˛ w kolejności odwrotnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 21 Lista inicjalizacyjna struct Komponent { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... Komponent( float Param ) { . . . } ... }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... KlasaBazowa( int Param ) { . . . } ... }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: protected KlasaBazowa Komponent Pole1; float Pole2; { // . . . . . . . . . . . . . . . . . . KlasaPochodna( ): KlasaBazowa(5), Pole1(10), Pole2(25) { . . . } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W liście inicjalizacyjnej musza˛ wystapić ˛ najpierw inicjalizatory klas bezpośrednio dziedziczonych (nie można inicjalizować w ten sposób klas pośrednio dziedziczonych), nastepnie ˛ inicjalizatory pól. Powinny one być wymienione zgodnie z kolejnościa˛ w jakiej wystepuj ˛ a˛ w definicji klasy. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 22 Przesłanianie nazw pól struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int Pole; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: public KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . int Pole; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna ObP; ObP. Pole = 10; ObP.KlasaBazowa:: Pole = 100; ObP.KlasaPochodna:: Pole = 10; ObP.KlasaPochodna::KlasaBazowa:: Pole = 100; } Przesłoniete ˛ pole zawsze można “odzyskać” poprzez wykorzystanie operatora zasiegu ˛ i podanie ich pełnej lub wzglednej ˛ nazwy kwalifikowanej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 23 Przesłanianie nazw metod struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int Pole; void Zeruj( ) { Pole = 0; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: public KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . int Pole; void Zeruj( ) { Pole = 0; KlasaBazowa::Zeruj( ); } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna ObP; ObP. Zeruj( ); ObP. KlasaBazowa::Zeruj( ); } Przesłoniete ˛ metody, podobnie jak przesłoniete ˛ pola, można “odzyskać” poprzez wykorzystanie operatora zasiegu ˛ i podanie nazwy kwalifikowanej. W demonstrowanym przykładzie w definicji metody Zeruj koniecznie należy użyć nazwe˛ kwalifikowana.˛ W przeciwnym przypadku dojdzie do zapetlenia ˛ po wywołaniu tej metody. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 24 Przesłanianie przeciaże ˛ ń struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . void Wyswietl( ) { cout << ”KlasaBazowa” << endl; } void WyswietlNapis( const char ∗wNap ) { cout << wNap << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: public KlasaBazowa { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . void Wyswietl( int Param ) { cout << Param << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna ObP; ObP.WyswietlNapis( ”Napis” ); ObP.Wyswietl( 123 ); h hh h ( ( h hh (( ( hh h ( ( (( h h ( ( h h ( ( (h h h hh (h ( h hh (( ( ObP.Wyswietl( h hh ( (( h ); h ( ( (( ObP.KlasaBazowa::Wyswietl( ); } Zdefiniowanie metody w klasie pochodnej przesłania wszystkie potencjalne jej “przeciażenia” ˛ z klasy bazowej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 25 Dziedziczenie pól statycznych struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static int Pole KBaz; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int KlasaBazowa:: Pole KBaz = 0; struct KlasaPochodna: public KlasaBazowa { int main( ) { KlasaPochodna }; // . . . . . . . . . . . . . . . . . . . . . . . ObP; ObP. Pole KBaz = 1; KlasaBazowa:: Pole KBaz = 2; KlasaPochodna:: Pole KBaz = 3; KlasaPochodna::KlasaBazowa:: Pole KBaz = 4; Wynik działania: cout << ObP. Pole KBaz << endl; 4 } Pola statyczne sa˛ dziedziczone tak jak zwykłe pola klasy. Obowiazuj ˛ a˛ dla nich te same reguły dostepu ˛ jak dla zwykłych pól. Ponadto do pól tych można odwołać bez pośrednictwa obiektu. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 26 Dziedziczenie pól statycznych struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static int Pole; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: public KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static int Pole; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int KlasaBazowa:: Pole = 0; int KlasaPochodna:: Pole = 0; int main( ) { KlasaBazowa:: Pole = 1; KlasaPochodna:: Pole = 2; KlasaPochodna::KlasaBazowa:: Pole = 3; cout << KlasaBazowa:: Pole << endl; cout << KlasaPochodna:: Pole << endl; } Wynik działania: 3 2 Dla pól statycznych obowiazuj ˛ a˛ te same reguły przesłaniania jak dla zwykłych pól. W podobny sposób można “odsłaniać” nazwy pól. Istnieje tu dodatkowa możliwość “odsłoniecia”, ˛ gdyż do takiego pola można odwołać sie˛ również poprzez klase˛ bazowa. ˛ c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 27 Dziedziczenie metod statycznych struct KlasaBazowa { static void Wyswietl( ) { cout << ”KlasaBazowa” << endl; } }; struct KlasaPochodna: public KlasaBazowa { static void Wyswietl( const char ∗wNapis ) { cout << wNapis << endl; } }; int main( ) { KlasaBazowa::Wyswietl( ); KlasaPochodna::Wyswietl(”Napis”); hh h h ( ( hh h ( (( h hh ( (( h( h h ( (( h h h( ( h h h ( ( ( h h h ( ( ( KlasaPochodna::Wyswietl( h h h ( ( ( h h h h ); ( ( ( KlasaPochodna::KlasaBazowa::Wyswietl( ); } Wynik działania: KlasaBazowa Napis KlasaBazowa Dla metod statycznych obowiazuj ˛ a˛ te same reguły przesłaniania jak dla zwykłych metod. Mechanizmy “odsłaniania” nazw metod sa˛ takie same jak w przypadku pól statycznych. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 28 Dziedziczenie przeciaże ˛ ń operatorów struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . operator double ( ) { return 10; } KlasaBazowa operator += ( double ) { return ∗this ; } void operator ++ ( ) { }; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: public KlasaBazowa { }; // . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna } ObP; double dd = ObP; ObP += 1; ++ObP; ObP += ObP; Przeciażenia ˛ operatorów sa˛ dziedziczone w ten sam sposób jak metody. Jest tylko jeden wyjatek ˛ ... c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 29 Operator podstawienia struct KlasaBazowa { KlasaBazowa & operator = ( const KlasaBazowa & ) { cout << ”Operator =” << endl; } }; struct KlasaPochodna: public KlasaBazowa { int main( ) { KlasaPochodna KlasaBazowa ObP1, ObP2; ObB; ObP1 = ObP2; cout << ”Nastepne podstawienie” << endl; h h hh h ( ( hh h ( (( hh h ( (( ( h h ( ( h h ( ( (h hh h h (h ( h h (( ( ObP1 = ObB; hh h h (( ( h h (( ( ( static cast<KlasaBazowa&>(ObP1) = ObB; } }; Wynik działania: Operator = Nastepne podstawienie Operator = Operator podstawienia nie jest dziedziczony. Wywoływany jest jedynie jako “składnik” domyślnego operatora podstawienia klasy pochodnej. Analogicznie zachowuje sie˛ konstruktor kopiujacy. ˛ c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 30 Konstruktor kopiujacy ˛ struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . KlasaBazowa( ) { } KlasaBazowa( const KlasaBazowa & ) { cout << ”Konstruktor kopiujacy” ˛ << endl; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: public KlasaBazowa { }; // . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna KlasaPochodna KlasaBazowa KlasaPochodna } ObP1; ObP2(ObP1); ObB; h h hh ( ( hh h h (( ( h hh (( ( h h ( ( h h( h ( h h( h ( (( h h h hh (( ( ObP3(ObB); h hh (( ( h h ( ( (( Wynik działania: Konstruktor kopiujacy ˛ Żaden z konstruktorów nie podlega dziedziczeniu. W przypadku konstruktora kopiujacego, ˛ podobnie jak operator przypisania, wywoływany jest on jedynie jako “składnik” domyślnego operatora podstawienia klasy pochodnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 31 Co nie jest dziedziczone Dziedziczeniu nie podlegaja: ˛ • operator przypisania, • konstruktory, • destruktor. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 32 Rzutowanie na podklase˛ i nadklase˛ struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int Pole KBazo; }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: public KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int Pole KPoch; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna ∗wObPoch = new KlasaPochodna; KlasaBazowa ∗wObBazo = wObPoch; h h hh hh h h h cout << wObPoch << endl; cout << wObBazo << endl; ( ( ( (( ( ( ( h h h hh ( (( ( h hh ( ( h h ( ( h hh h (( ( wObPoch = wObBazo; hh h (( ( h h h ( ( (( wObPoch = static cast<KlasaPochodna∗>(wObBazo); cout << wObPoch << endl; } Wynik działania: 0x804a008 0x804a008 0x804a008 Rzutowanie na podklase˛ realizowane jest niejawnie. Rzutowanie na nadklase˛ musi być zawsze jawne. Zrealizować je można posługujac ˛ sie˛ operatorem rzutowania statycznego. W tym przypadku brak różnicy w adresach wynika z tego, że obiekt klasy bazowej znajduje sie˛ “na poczatku” ˛ obiektu klasy pochodnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 33 Rzutowanie na podklase˛ i nadklase˛ struct KlasaBazowa1 { int Pole KBazo1; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaBazowa2 { int Pole KBazo2; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: KlasaBazowa1, KlasaBazowa2 { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int Pole KPoch; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna KlasaBazowa2 ∗wObPocho = new KlasaPochodna; ∗wObBazo2 = wObPocho; wObPocho = static cast<KlasaPochodna∗>(wObBazo2); cout << wObPocho << endl; } cout << wObPocho << endl; cout << wObBazo2 << endl; Wynik działania: 0x804a008 0x804a00c 0x804a008 W tym przykładzie rzutowanie wiaże ˛ sie˛ z fizyczna˛ zmiana˛ adresu. Operacja realizowana jest niejawnie. Różnica adresów zwiazana ˛ jest z tym, że obiekt podklasy KlasaBazowa2 jest drugi w kolejności w strukturze obiektu KlasaPochodna. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 34 Rzutowanie na podklase˛ - rzutowanie w góre˛ Rzutowanie ”w góre” ˛ jest rzutowaniem na klase˛ bazowa. ˛ Tego typu rzutowanie zawsze sie˛ powiedzie, gdyż obiekt klasy pochodnej musi zawierać podobiekt klasy bazowej. Z tego powodu rzutowanie to może być realizowane niejawnie. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 35 Rzutowanie na nadklase˛ - rzutowanie w dół Rzutowanie ”w dół” jest rzutowaniem na klase˛ pochodna. ˛ Ze wzgledu ˛ na to, że obiekt klasy bazowej nie zawsze musi być składnikiem obiektu klasy pochodnej (np. może wystepować ˛ samodzielnie), rzutowanie to może nie powieść sie. ˛ c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 36 Błedne ˛ rzutowanie “w dół” struct KlasaBazowa1 { int Pole KBazo1; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaBazowa2 { int Pole KBazo2; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: KlasaBazowa1, KlasaBazowa2 { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int Pole KPoch; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaBazowa2 ∗wObBazo2 = new KlasaBazowa2; KlasaPochodna ∗wObPocho = static cast<KlasaPochodna∗>(wObBazo2); cout << wObBazo2 << endl; cout << wObPocho << endl; } Wynik działania: 0x804a008 0x804a004 W rzutowaniu statycznym nie jest sprawdzana poprawność jego realizacji. W tym przypadku nie jest to w ogóle możliwe, gdyż KlasaPochodna nie jest klasa˛ polimorficzna. ˛ Rezultatem operacji jest adres do nie istniejacego ˛ obiektu. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 37 Rzutowanie referencji struct KlasaBazowa1 { int Pole KBazo1; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaBazowa2 { int Pole KBazo2; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: KlasaBazowa1, KlasaBazowa2 { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int Pole KPoch; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int main( ) { KlasaPochodna KlasaBazowa2 ObPocho; &rObBazo2 = ObPocho; cout << &ObPocho << endl; cout << &rObBazo2 << endl; KlasaPochodna &rObPocho = static cast<KlasaPochodna&>(rObBazo2); cout << &rObPocho << endl; } Wynik działania: 0xbf9c2de0 0xbf9c2de4 0xbf9c2de0 Rzutowanie na referencje˛ realizowane jest zgodnie z tymi samymi regułami jak rzutowanie wskaźników. Różnica adresów zwiazana ˛ jest z tym, że obiekt podklasy KlasaBazowa2 jest drugi w kolejności w strukturze obiektu KlasaPochodna. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 38 Niejawne rzutowanie w liście parametrów funkcji struct KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int Pole KBazo; }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaPochodna: public KlasaBazowa { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . int Pole KPoch; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . void Wyswietl( const KlasaBazowa∗ wOb ) { cout << wOb-> Pole KBazo << endl; } void Wyswietl( const KlasaBazowa& Ob ) { cout << Ob. Pole KBazo << endl; } int main( ) { KlasaPochodna ObPocho; ObPocho. Pole KBazo = 102; Wyswietl(&ObPocho); Wyswietl(ObPocho); } Wynik działania: 102 102 Niejawne rzutowanie pozwala wykorzystać udogodnienia stworzone dla klasy bazowej. Możemy z nich skorzystać gdy dysponujemy obiektem klasy pochodnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 39 Kompozycja wersus dziedziczenie struct KlasaA { // . . . . . . . . . . . . . . . . . . . . . . . . . . int PoleA; ... }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaA { // . . . . . . . . . . . . . . . . . . . . . . . . . . int PoleA; ... }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaB { // . . . . . . . . . . . . . . . . . . . . . . . . . KlasaA PoleA; PoleB; int }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct KlasaB: public KlasaA { // . . . . . . . . . int PoleB; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zalety: Zalety: • Pozwala na odseparowanie interfejsu klasy obiektu bed ˛ acego ˛ komponentem. • Umożliwia utworzenie wielu komponentów tego samego typu. • Pozwala na niejawne rzutowania w góre˛ oraz jawne rzutowania w dół. Dzieki ˛ temu z poziomu podobiektu można łatwo “przejść” na poziom obiektu. • Nie “zaśmieca” przestrzeni nazw klasy do- • Pozwala na przesłoniecie ˛ cz˛eści interfejsu datkowymi nazwami z przestrzeni nazw komponentu. klasy bazowej, jeżeli musi on zostać zmieniony na poziomie klasy pochodnej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 40 Przykład wykorzystania komponentów struct Wektor2f { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . float x, y; }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class Odcinek { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wektor2f Po, Pn; public : const Wektor2f & WezPo( ) const { return Po; } const Wektor2f & WezPn( ) const { return Pn; } Wektor2f & UzyjPo( ) { return Po; } Wektor2f & UzyjPn( ) { return Pn; } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Podstawowa˛ zaleta˛ kompozycji jest możliwość definiowania wielu komponentów tego samego typu. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 41 Przykład pośredniego dziedziczenia tej samej klasy struct Wektor2f { float x, y; } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct Wektor2f A: Wektor2f { }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct Wektor2f B: Wektor2f { }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . class Odcinek: Wektor2f A, Wektor2f B { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . public : const Wektor2f & WezPo( ) const { return static cast<const Wektor2f A&>(∗this ); } const Wektor2f & WezPn( ) const { return static cast<const Wektor2f B&>(∗this ); } Wektor2f & UzyjPo( ) { return static cast<Wektor2f A&>(∗this ); } Wektor2f & UzyjPn( ) { return static cast<Wektor2f B&>(∗this ); } }; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . T˛e sama˛ klase˛ można dziedziczyć wielokrotnie w sposób pośredni. Klasy pośrednie umożliwiaja˛ ˛ struktur poprzez rzutowanie w góre˛ jawnie i niejawne. dostep ˛ do pożadanych c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 42 Podsumowanie • Dziedziczenie pozwala na zamodelowanie hierarchii pojeć. ˛ • Umożliwia przyrostowe tworzenie oprogramowania. • Pozwala na wielokrotne wykorzystanie tego samego kodu. • Nie wszystkie elementy klasy podlegaja˛ dziedziczeniu (dotyczy to operatora przypisania, konstruktorów i destruktora). • Rzutowanie “w góre” ˛ pozwala na korzystanie ze wszystkich udogodnień stworzonych dla klasy bazowej. c 2005–2008 Bogdan Kreczmer Copyright Dziedziczenie 43