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