Programowanie obiektowe w C++ Wykład 4

Transkrypt

Programowanie obiektowe w C++ Wykład 4
Programowanie obiektowe w C++
Wykªad 4
dr Lidia St¦pie«
Akademia im. Jana Dªugosza
w Cz¦stochowie
L. St¦pie« (AJD)
Programowanie obiektowe w C++
1 / 26
Dziedziczenie - podstawy
Denicja klasy dziedzicz¡cej w sposób publiczny po innej klasie:
class Pochodna : public Bazowa {
// tre±¢ klasy
};
Klasa pochodna dziedziczy po klasie bazowej jej pola i funkcje
skªadowe.
Klasa pochodna oprócz wªasnych skªadowych b¦dzie zatem posiadaªa
równie» skªadowe z klasy Bazowa.
L. St¦pie« (AJD)
Programowanie obiektowe w C++
2 / 26
Przykªad 1
class Samochod{
public:
Samochod();
void Info() const;
bool osobowy;
};
class Fiat : public Samochod{
public:
Fiat();
};
class Star : public Samochod{
public:
Star();
};
L. St¦pie« (AJD)
Programowanie obiektowe w C++
3 / 26
Przykªad 1 cd.
Samochod::Samochod(){}
void Samochod::Info() const {
if osobowy
cout << "Samochod sobowy" << endl;
else
cout << "Samochod ciezarowy" << endl;
}
Fiat:: Fiat(){
osobowy = true;
}
Star:: Star(){
osobowy = false;
}
L. St¦pie« (AJD)
Programowanie obiektowe w C++
4 / 26
Przykªad 1 cd.
int main(){
Fiat a1;
cout << "Samochod: ";
a1.info();
Star a2;
cout << "Samochod: ";
a2.info();
// Naruszenie hermetyzacji
a2.osobowy = true;
}
return 0;
L. St¦pie« (AJD)
Programowanie obiektowe w C++
5 / 26
Skªadowe prywatne i chronione w klasie bazowej
Specykatora private u»ywamy, gdy chcemy uchroni¢ skªadowe
zarówno przed dost¦pem z zewn¡trz, jak i przed dost¦pem w klasach
pochodnych.
Specykatora protected u»ywamy, gdy chcemy uchroni¢ skªadowe
przed dost¦pem z zewn¡trz, ale jednocze±nie mie¢ je do dyspozycji w
klasach pochodnych.
L. St¦pie« (AJD)
Programowanie obiektowe w C++
6 / 26
Rodzaje dziedziczenia
W dziedziczeniu publicznym skªadowe publiczne klasy bazowej s¡
dziedziczone jako publiczne, a skªadowe chronione jako chronione.
W dziedziczeniu chronionym skªadowe publiczne oraz chronione s¡
dziedziczone jako chronione.
W dziedziczeniu prywatnym skªadowe publiczne oraz chronione s¡
dziedziczone jako prywatne.
Gdy nie jest podany typ dziedziczenia, to domy±lne jest dziedziczenie
prywatne.
Skªadowe prywatne s¡ zawsze dziedziczone jako prywatne.
L. St¦pie« (AJD)
Programowanie obiektowe w C++
7 / 26
Dziedziczenie a konstruktory
Podczas tworzenia obiektu klasy pochodnej wywoªywany jest
konstruktor domy±lny klasy bazowej, o ile taki konstruktor istnieje.
Je»eli w klasie bazowej nie istnieje konstruktor domy±lny, nale»y jawnie
wywoªa¢ jeden z pozostaªych konstruktorów.
Jawne wywolanie konstruktora klasy bazowej:
Pochodna::Pochodna(argumenty) : Bazowa(argumenty) {
// tre±¢ konstruktora
}
L. St¦pie« (AJD)
Programowanie obiektowe w C++
8 / 26
Przykªad 2
class Samochod{
public:
Samochod(bool);
void Info() const;
protected:
bool osobowy;
};
class Fiat : public Samochod{
public:
Fiat();
void Info() const;
};
class Star : public Samochod{
public:
Star();
void Info() const;
};
L. St¦pie« (AJD)
Programowanie obiektowe w C++
9 / 26
Przykªad 2 cd.
Samochod::Samochod(bool osobowy) : osobowy(osobowy){}
void Samochod::Info() const {
if osobowy
cout << "Samochod sobowy" << endl;
else
cout << "Samochod ciezarowy" << endl;
}
Fiat:: Fiat() : Samochod(true){ }
void Fiat::Info() const {
Samochod::Info();
cout << "Fiat" << endl;
}
Star:: Star() : Samochod(false){ }
void Star::Info() const {
Samochod::Info();
cout << "Star" << endl;
}
L. St¦pie« (AJD)
Programowanie obiektowe w C++
10 / 26
Przykªad 2 cd.
int main(){
Fiat a1;
cout << "Samochod: ";
a1.info();
a1.Samochod::Info();
Star a2;
cout << "Samochod: ";
a2.info();
a2.Samochod::Info();
}
return 0;
L. St¦pie« (AJD)
Programowanie obiektowe w C++
11 / 26
UWAGI
W pierwszej kolejno±ci tworzony jest obiekt klasy bazowej.
Konstruktor klasy pochodnej powinien przekazywa¢ dane klasy
bazowej do jej konstruktora za pomoc¡ listy inicjalizacyjnej.
Konstruktor klasy pochodnej powinien inicjalizowa¢ wszystkie dane
skªadowe, które zostaªy dodane do tej klasy.
Kiedy obiekt klasy pochodnej jest usuwany, najpierw wywoªywany jest
destruktor klasy pochodnej, a nast¦pnie destruktor klasy bazowej.
Mo»na deklarowa¢ referencje oraz wska¹niki do obiektów klasy
bazowej i przypisywa¢ im zarówno obiekty klasy bazowej, jak i
pochodnej. Ale nie na odwrót!
L. St¦pie« (AJD)
Programowanie obiektowe w C++
12 / 26
Przesªanianie pól i metod
Gdy w klasie pochodnej znajduje si¦ metoda f o takiej samej nazwie i
argumentach jak metoda znajduj¡ca si¦ w klasie bazowej, to mamy do
czynienia ze zjawiskiem nadpisania metody.
Aby wywoªa¢ w klasie pochodnej nadpisan¡ metod¦
nale»y u»y¢ konstrukcji: Bazowa :: f (argumenty ).
f z klasy bazowej
Gdy w klasie pochodnej znajduje si¦ pole p o takiej samej nazwie jak
pole znajduj¡ce si¦ w klasie bazowej, to mamy do czynienia ze
zjawiskiem przesªoni¦tego pola.
Aby w klasie pochodnej odwoªa¢ si¦ do przesªoni¦tego pola
bazowej nale»y u»y¢ konstrukcji: Bazowa :: p .
L. St¦pie« (AJD)
Programowanie obiektowe w C++
p z klasy
13 / 26
Przykªad 3
Niech A b¦dzie klas¡ bazow¡, B jest klas¡ dziedzicz¡c¡ publicznie po A,
f () jest niestatyczn¡ metod¡ z klasy A oraz f () jest nadpisana w klasie B .
Zaªó»my, »e dane s¡ deklaracje:
B b; A& r = b; A* p = &b;
Która z metod
f
()
(z klasy bazowej czy pochodnej) zostanie
wywoªana?
b.f();
r.f();
p->f();
L. St¦pie« (AJD)
Programowanie obiektowe w C++
14 / 26
Metody wirtualne
Aby metoda klasy staªa si¦ wirtualna, nale»y jej nagªówek w deklaracji
klasy poprzedzi¢ sªowem kluczowym virtual .
Metody wirtualne stosujemy wtedy, kiedy wiemy, »e w klasie
pochodnej b¦dziemy powtórnie j¡ deniowa¢.
Wirtualno±¢ pozwala wybra¢ wersj¦ metody na podstawie typu obiektu
zamiast na podstawie typu referencji lub wska¹nika.
Deklaracja metody w klasie bazowej za pomoc¡ sªowa kluczowego
virtual powoduje, »e funkcja ta jest wirtualna zarówno w klasie
bazowej, jak i we wszystkich klasach od niej pochodnych (ª¡cznie z
klasami pochodnymi klas pochodnych).
L. St¦pie« (AJD)
Programowanie obiektowe w C++
15 / 26
Przykªad 3
class Samochod{
public:
Samochod(bool);
virtual void Info() const;
protected:
bool osobowy;
};
class Fiat : public Samochod{
public:
Fiat();
virtual void Info() const;
};
class Star : public Samochod{
public:
Star();
virtual void Info() const;
};
L. St¦pie« (AJD)
Programowanie obiektowe w C++
16 / 26
Przykªad 3 cd.
Samochod::Samochod(bool osobowy) : osobowy(osobowy){}
void Samochod::Info() const {
if osobowy
cout << "Samochod sobowy" << endl;
else
cout << "Samochod ciezarowy" << endl;
}
Fiat:: Fiat() : Samochod(true){ }
void Fiat::Info() const {
Samochod::Info();
cout << "Fiat" << endl;
}
Star:: Star() : Samochod(false){ }
void Star::Info() const {
Samochod::Info();
cout << "Star" << endl;
}
L. St¦pie« (AJD)
Programowanie obiektowe w C++
17 / 26
Przykªad 3 cd.
int main(){
Samochod *ps = new Fiat;
cout << "Samochod: ";
ps->info();
Star a2;
Samochod &rs = a2;
cout << "Samochod: ";
rs.info();
}
return 0;
L. St¦pie« (AJD)
Programowanie obiektowe w C++
18 / 26
Metody wirtualne
Konstruktory nie mog¡ by¢ wirtualne. Tworzenie obiektu klasy
pochodnej wymaga wywoªania konstruktora klasy pochodnej, a nie
bazowej. Konstruktor klasy pochodnej u»ywa konstruktora klasy
bazowej, a nie dziedziczy go. Nie ma wi¦c powodu, aby tworzy¢
konstruktory wirtualne.
Je±li klasa ma by¢ wykorzystywana jako bazowa, to destruktory
powinny by¢ wirtualne.
A *pa = new B; // poprawnie; A to klasa bazowa B
....
delete pa;
// ~A() czy ~B()?
Powinno si¦ udost¦pnia¢ w klasie bazowej destruktor wirtualny, nawet
wtedy kiedy klasa ta nie potrzebuje destruktora.
L. St¦pie« (AJD)
Programowanie obiektowe w C++
19 / 26
UWAGI
Funkcje zaprzyja¹nione nie mog¡ by¢ wirtualne, poniewa» nie s¡
skªadowymi klasy, a tylko funkcje skªadowe mog¡ by¢ wirtualne.
Mo»na u»y¢ metod wirtualnych wewnatrz funkcji zaprzyja¹nionych i w
ten sposób obej±¢ powy»sze ograniczenie.
Je±li w klasie pochodnej nie ma nowej denicji funkcji, wtedy klasa
u»ywa wersji tej funkcji z klasy bazowej. Je»eli klasa jest ogniwem
dªugiego ªa«cucha dziedziczenia, wtedy u»ywa wersji tej funkcji
zdeniowanej najbli»ej.
L. St¦pie« (AJD)
Programowanie obiektowe w C++
20 / 26
Ukrywanie metod w wyniku powtórnej denicji
class A{
public:
virtual void show(int) const;
...
};
class B : public A{
public:
virtual void show() const;
...
};
B b;
b.show(); // poprawne
b.show(5); // niepoprawne
L. St¦pie« (AJD)
Programowanie obiektowe w C++
21 / 26
UWAGI
W wyniku powtórnej denicji funkcji skªadowej w klasie pochodnej
ró»ni¡cej si¦ argumentem, powstaje jedna wersja tej funkcji, a nie dwie
przeci¡»one. Funkcja z klasy bazowej zostaje ukryta.
Nowa denicja ukrywa wszystkie metody klasy bazowej o tej samej
nazwie, niezaleznie od ich sygnatur.
Je±li redeniujemy odziedziczon¡ metod¦, musi ona dokªadnie pasowa¢
do prototypu funkcji z klasy bazowej.
Istnieje mozliwo±¢ zmiany zwracanego przez funkcj¦ typu ze wska¹nika
lub referencji klasy bazowej na wska¹nik lub referencj¦ klasy
pochodnej. Jest to kowariancja zwracanego typu.
Je±li deklaracja funkcji w klasie bazowej jest przeci¡»ona, to w klasie
pochodnej musimy powtórnie zdeniowa¢ wszystkie wersje z klasy
bazowej.
L. St¦pie« (AJD)
Programowanie obiektowe w C++
22 / 26
Abstrakcyjne klasy bazowe
W j¦zyku C++ istnieje sposób na umieszczenie funkcji bez
implementacji w postaci funkcji czysto wirtualnej.
Funkcja czysto wirtualna ma wyra»enie = 0 na ko«cu deklaracji.
Aby klasa byªa prawdziw¡ klas¡ czysto abstrakcyjn¡, musi mie¢
przynajmniej jedn¡ funkcj¦ czysto wirtualn¡.
Je±li klasa zawiera metod¦ czysto wirtualn¡, nie mo»emy tworzy¢
obiektów tej klasy. St¡d klasy te s¡ wykorzystywane jedynie jako klasy
bazowe.
Ka»d¡ metod¦ czysto wirtualn¡ klasy bazowej nale»y przeci¡»y¢ w
klasie pochodnej, w przeciwnym przypadku klasa pochodna nadal
pozostanie czysto abstrakcyjn¡.
L. St¦pie« (AJD)
Programowanie obiektowe w C++
23 / 26
override - w C++11 oznacza, »e dana metoda w klasie
pochodnej przesªania metod¦ wirtualn¡ z klasy bazowej
class B {
virtual void x() { }
};
class D : public B {
virtual void x() override { } //OK
};
class E : public B {
virtual void x() const override { } //Bª¡d
};
class F : public B {
virtual void y() override { } //Bª¡d
};
L. St¦pie« (AJD)
Programowanie obiektowe w C++
24 / 26
Przykªad 4
class Ksztalt {
public:
virtual ~Ksztalt() { }
virtual void rysuj() = 0; //ka»dy okre±lony
//ksztaªt musi da¢ sie narysowa¢
};
class Kolo : public Ksztalt {
public:
virtual void rysuj() {
std::cout << "Rysuje kolo: ( )" << std::endl; }
};
class Kwadrat : public Ksztalt {
public:
virtual void rysuj() {
std::cout << "Rysuje kwadrat: [ ]" << std::endl; }
};
L. St¦pie« (AJD)
Programowanie obiektowe w C++
25 / 26
Przykªad 4 cd.
int main(){
//Ksztalt a;
Ksztalt * a = new Kolo, * b = new Kwadrat;
a->rysuj();
b->rysuj();
}
delete a;
delete b;
L. St¦pie« (AJD)
Programowanie obiektowe w C++
26 / 26

Podobne dokumenty