Programowanie 2. Język C++. Wykład 9. 1 9.1 Ukrywanie metod

Transkrypt

Programowanie 2. Język C++. Wykład 9. 1 9.1 Ukrywanie metod
Programowanie 2. Język C++. Wykład 9.
9.1 Ukrywanie metod, metody nadpisane ............................................................................................................ 1
9.2 Metody wirtualne, wirtualny destruktor .......................................................................................................... 2
9.3 Metody czysto wirtualne ............................................................................................................................... 6
9.4 Klasy abstrakcyjne ....................................................................................................................................... 7
9.5 Wielodziedziczenie ...................................................................................................................................... 9
9.1 Ukrywanie metod, metody nadpisane
Metoda z klasy bazowej jest zasłonięta przez metodę z klasy pochodnej.
To znaczy, Ŝe obiekty klasy pochodnej nie mają dostępu do ukrytych metod z klasy bazowej.
Nadpisanie metody (method overriding) z klasy bazowej oznacza zdefiniowanie w klasie pochodnej metody o
takiej samej sygnaturze.
Zwracany typ metody nadpisanej moŜe być taki, jak metody nadpisanej lub ‘kowariantny’ z klasą bazową.
Przykład 1. Metoda z klasy B zasłania obiektom typu B metodę z klasy A (w09-01-ukrywanieMetod.cpp).
#include <iostream>
using namespace std;
class A {
public:
A(){cout << "A()" << endl;}
virtual ~A(){cout << "~A()" << endl;}
void
metoda() const { cout << "metoda() w A" << endl; }
};
class B : public A {
public:
B(){cout << "B()" << endl;}
~B(){cout << "~B()" << endl;}
void metoda() const { cout << "metoda() w B" << endl; }
};
void main() {
A a;
B b;
a.metoda();
b.metoda();
// metoda() z klasy A
// metoda() z klasy B
// obiekt b nie ma dostępu do metoda() z A
// metoda() z A jest zasłonięta przez metoda() z B
b.A::metoda();
// metoda() z klasy A
A * p = new B;
p->metoda();
// metoda() z klasy A
delete p;
}
1
Programowanie 2. Język C++. Wykład 9.
9.2 Metody wirtualne, wirtualny destruktor
Definicja metody wirtualnej:
virtual <zwracanyTyp> nazwaFunkcji(<typArg1> <nazwaArg1>,… ){ <instrukcje>; }
Metoda wirtualna jest zdefiniowana i zaimplementowana w klasie bazowej.
W klasie pochodnej jest ponownie zaimplementowana.
Uwaga: metody wirtualne nie wymuszają implementacji w klasie pochodnej, poniewaŜ mają domyślną
implementację w klasie bazowej.
Klasa która zawiera metodę wirtualną nazywa się klasą polimorficzną.
Metody statyczne nie mogą być deklarowane jako wirtualne.
Nie moŜna definiować funkcji wirtualnych, tzn. funkcja musi naleŜeć do jakieś klasy aby być wirtualną.
Jak kompilator odnajduje wirtualne metody w klasach?
Kompilator tworzy tablicę, zwaną VTABLE, do której zapisuje adresy wirtualnych metod danej klasy.
KaŜda klasa zawierająca wirtualną metodę posiada wskaźnik (vpointer) który wskazuje instancji klasy na adres
tablicy VTABLE (zawierającą adresy wirtualnych metod).
Przykład 1. Metody wirtualne (w09-02-metodyWirtualne.cpp).
#include <iostream>
using namespace std;
class A {
public:
virtual void metoda() const {
cout << "metoda() w A" << endl;
// void metoda() const {
cout << "metoda() w A" << endl; }
};
class B : public A {
public:
void metoda() const {
};
void funk(A& a) {
cout << "metoda() w B" << endl;
}
}
a.metoda(); }
void main() {
B b;
A *pa;
pa= &b;
pa->metoda();
b.metoda();
A a;
pa= &a;
pa->metoda();
a.metoda();
// metoda() z B
// metoda() z A
funk(b); // metoda() w B
//
//
gdy metoda() w A nie jest wirtualna, to
funk(b); // metoda() w A
}
2
Programowanie 2. Język C++. Wykład 9.
W przypadku definiowania obiektów na stercie za pomocą ‘upcast’, naleŜy zadeklarować wirtualnego destruktora.
Przykład 2. Definiowanie obiektów ‘upcast’.
class A {};
class B : public A {};
A *p= new B;
// …
delete p;
// upcast
Przykład 3. Wywołanie wirtualnego destruktora przy usuwaniu obiektu ze sterty
(w09-03-wirtualnyDestruktor.cpp).
#include<iostream>
using namespace std;
class A {
public:
A(){ cout << "A()" << endl; }
virtual ~A(){ cout << "~A()" << endl; }
// ~A(){cout << "~A()" << endl;}
};
class B :public A {
public:
B(){ cout << "B()" << endl; }
~B(){ cout << "~B()" << endl; }
};
void main() {
A *p = new B;
// upcast
delete p;
}
//---------------------------------------------------+
// Wynik działania programu ze zwykłym destruktorem
/*
A()
B()
~A() // brak destruktora ~B()
*/
//---------------------------------------------------+
//---------------------------------------------------+
// Wynik działania programu z wirtualnym destruktorem
/*
A()
B()
~B()
~A()
*/
//---------------------------------------------------+
3
Programowanie 2. Język C++. Wykład 9.
Przykład 4. Metody wirtualne, wirtualny destruktor, tworzenie obiektów na stercie upcast
(w09-04-metodyWirtualne.cpp).
#include <iostream>
using namespace std;
class A {
public:
A(){cout << "A()" << endl;}
virtual ~A(){cout << "~A()" << endl;}
void metoda1() const { cout << "metoda1() w A" << endl; }
virtual void metoda2() const { cout << "metoda2() w A" << endl; }
};
class B : public A {
public:
B(){cout << "B()" << endl;}
~B(){cout << "~B()" << endl;}
void metoda1() const {
void metoda2() const {
cout << "metoda1() w B" << endl; }
cout << "metoda2() w B" << endl; }
};
void main() {
A *p = new B;
// upcast
p->metoda1();
// wywołana jest metoda() z klasy A
p->metoda2();
// wywołana jest metoda() z klasy B
p->A::metoda2();
// wywołana jest metoda() z klasy A
delete p;
}
4
Programowanie 2. Język C++. Wykład 9.
Deklaracja metody wirtualnej nie musi zawierać specyfikatora virtual.
Metoda zdefiniowana jako wirtualna w klasie bazowej, nadpisana w klasie pochodnej jest teŜ wirtualna.
Przykład 5. (w09-05-metodyWirtualnebezVirtual.cpp)
#include <iostream>
using namespace std;
class A {
public:
A(){cout << "A()" << endl; }
virtual ~A(){cout << "~A()" << endl; }
virtual void metoda() const { cout << "metoda() w A" << endl; }
//void metoda() const { cout << "metoda() w A" << endl; }
};
class B : public A {
public:
B(){cout << "B()" << endl; }
virtual ~B(){cout << "~B()" << endl; }
// metoda() jest wirtulna
void metoda() const { cout << "metoda() w B" << endl; }
};
class C : public B {
public:
C(){cout << "C()" << endl; }
~C(){cout << "~C()" << endl; }
void metoda() const { cout << "metoda() w C" << endl; }
};
void main() {
A *p = new B;
p->metoda();
// wywołana jest metoda() z klasy B
p->A::metoda();
B *pp = new C;
pp->metoda(); // wywołana jest metoda() z klasy C
pp->B::metoda();
A *ppp = new C;
ppp->metoda(); // wywołana jest metoda() z klasy C
delete p;
delete pp;
delete ppp;
}
5
Programowanie 2. Język C++. Wykład 9.
Przykład 6. Metoda fun(int) z klasy B zasłania metodę z fun() klasy A (w09-06-metodyWirtualne-f(int).cpp).
#include <iostream>
using namespace std;
class A {
public:
A(){cout << "A()" << endl;}
virtual ~A(){cout << "~A()" << endl;}
virtual void metoda() const { cout << "metoda() w A" << endl; }
virtual void fun() const { cout << "fun() w A" << endl; }
};
class B : public A {
public:
B(){cout << "B()" << endl;}
~B(){cout << "~B()" << endl;}
void metoda() const { cout << "metoda() w B" << endl; }
void fun(int x) const { cout << "fun(int) w B, x = " << x << endl; }
};
void main() {
B b;
// b.fun(); // błąd, fun(int) z B zasłania fun() z A
b.fun(30);
A *p = new B;
p->metoda();
p->A::metoda();
// wywołana jest metoda() z klasy B
// wywołana jest metoda() z A
p->fun();
// p->fun(10);
// p->B::fun(20);
// wywołana jest fun() z klasy A
// błąd, nie moŜna wywołać fun(int) z B
// błąd, nie moŜna wywołać fun(int) z B
delete p;
}
9.3 Metody czysto wirtualne
Definicja metody czysto wirtualnej:
virtual <zwracanyTyp> nazwaFunkcji(<typArg1> <nazwaArg1>,… ) = 0;
Przykład 1. Definicja metody czysto wirtualnej.
class Abstrakcyjna {
public:
virtual void metoda() const = 0;
};
6
Programowanie 2. Język C++. Wykład 9.
9.4 Klasy abstrakcyjne
Klasa jest abstrakcyjna jeŜeli zawiera lub dziedziczy przynajmniej jedną metodę czysto wirtualną.
Klasa abstrakcyjna nie moŜe być dziedziczona, tzn. moŜe być tylko klasą od której się dziedziczy.
Nie moŜna utworzyć instancji (obiektu) klasy abstrakcyjnej.
MoŜna definiować obiekty typy referencyjnego lub wskaźniki klasy abstrakcyjnej.
Uwaga: deklaracja metody czysto wirtualnej, definiowanie klasy abstrakcyjnej, wymusza w klasie pochodnej
implementację metody czysto wirtualnej.
Przykład 1. Definicja klasy abstrakcyjna (w09-07-klasaAbstrakcyjna.cpp)
#include <iostream>
using namespace std;
class Abs{
public:
Abs(){cout << "Abs()" << endl; }
virtual ~Abs(){cout << "~Abs()" << endl; }
virtual void funkcja() const = 0;
void func() { cout << "func() w Abs" << endl; }
};
// implementacja metody czysto wirtualnej w klasie abstrakcyjnej
// implementacja nie inline
void Abs::funkcja() const {
cout << "funkcja() w Abs" << endl; }
class B : public Abs {
public:
B(){cout << "B()" << endl; }
~B(){cout << "~B()" << endl;}
// funkcja czysto wirtualna musi być implemtowana w klasie B
// jeŜeli nie, to klasa B będze rownieŜ abstrakcyjna
void funkcja() const { cout << "funkcja() w B " << endl; }
void func() { cout << "func() w B" << endl; }
};
void main( )
{
// Abs a;
// błąd, nie moŜna utworzyć instancji klasy abstakcyjnej
B b;
b.func();
b.funkcja();
// func() z klasy B
// funkcja() z klasy B
Abs * p = new B;
p->func();
delete p;
// func() z klasy Abs
}
7
Programowanie 2. Język C++. Wykład 9.
Brak implementacji metody czysto wirtualnej w klasie pochodnej powoduje, Ŝe klasa pochodna jest klasą
abstrakcyjną
Przykład 2. Brak implementacji w klasie B metody() z klasy Abs powoduje, Ŝe B jest klasą abstrakcyjną
(w09-08-klasyAbstrakcyjne.cpp)
#include <iostream>
using namespace std;
class Abs {
public:
Abs(){cout << "Abs()" << endl;}
~Abs(){cout << "~Abs()" << endl;}
virtual void metoda() = 0; // metoda czysto wirtualna
};
class A : virtual public Abs {
public:
A(){cout << "A()" << endl;}
~A(){cout << "~A()" << endl;}
private:
void metoda(){}
// implementacja metody czysto wirtualnej
};
class B : virtual public Abs {
public:
B(){cout << "B()" << endl;}
~B(){cout << "~B()" << endl;}
// brak implementacji metody czysto wirtualnej
};
class C : public A, public B {
public:
C(){cout << "C()" << endl;}
~C(){cout << "~C()" << endl;}
private:
void metoda(){}
// implementacja metody czysto wirtualnej
};
void main()
{
A a;
//
B b;
// B jest klasą abstrakcyjną
C c;
}
8
Programowanie 2. Język C++. Wykład 9.
9.5 Wielodziedziczenie
Przykład 1. Wielodziedziczenie typu public.
class A {};
class B {};
class C : public A, public B {};
Przykład 2. Klasy A i B są bazowa dla klasy C (w09-09-wielodziedziczenie.cpp).
#include <iostream>
using namespace std;
class A {
public:
A(){ cout << "A()" << endl;}
~A(){ cout << "~A()" << endl;}
};
class B {
public:
B(){ cout << "B()" << endl;}
~B(){cout << "~B()" << endl;}
};
class C : public A, public B {
public:
C(){ cout << "C()" << endl;}
~C(){cout << "~C()" << endl;}
};
void main() {
C c;
}
//-------------------------------------------+
// Wynik działania programu
/*
A()
B()
C()
~C()
~B()
~A()
*/
//-------------------------------------------+
9
Programowanie 2. Język C++. Wykład 9.
Przykład 3. Wielodziedziczenie biblioteka iostream.
10
Programowanie 2. Język C++. Wykład 9.
Przykład 4. Wirtualne dziedziczenie (w09-10-wirtualneDziedziczenie.cpp).
#include <iostream>
using namespace std;
class A {
public:
A(){cout << "A()" << endl;}
~A(){cout << "~A()" << endl;}
};
// class B : public A {
class B : virtual public A {
public:
B(){cout << "B()" << endl;}
~B(){cout << "~B()" << endl;}
};
// class C : public A {
class C : virtual public A {
public:
C(){cout << "C()" << endl;}
~C(){cout << "~C()" << endl;}
};
class D : public B, public C {
public:
D(){ cout << "D()" << endl;}
~D(){ cout << "~D()" << endl;}
};
void main()
{
D d;
}
11
Programowanie 2. Język C++. Wykład 9.
//-----------------------------------------------------+
// Wynik działania programu z wirtualnym dziedziczeniem
/*
A()
B()
C()
D()
~D()
~C()
~B()
~A()
*/
//-----------------------------------------------------+
//-----------------------------------------------------+
// Wynik działania programu ze zwykłym dziedziczeniem
/*
A()
B()
A()
C()
D()
~D()
~C()
~A()
~B()
~A()
*/
//-----------------------------------------------------+
12

Podobne dokumenty