pokazB();
return;
}//---------------------------------------------------------
Dzięki tak skonstruowanemu odwołaniu aktualna wersji funkcji pokazB(), która powinna być w danym momencie działania programu wywołana, ustalana jest w głównej funkcji main() na podstawie typu, do którego odwołuje się jej parametr aktualny.
Listing 4.4. Kod głównego modułu Unit_R4_04.cpp projektu Projekt_R4_04.bdsproj wykorzystującego odwołanie do klasy polimorficznej
#include
#pragma hdrstop
using namespace std;
class TBazowa {
public:
virtual void __fastcall pokazB()
{cout << "Jestem klasa bazowa" << endl; }
};
//---------------------------------------------------------
class TPochodna1 : public TBazowa {
public:
/*virtual*/ void __fastcall pokazB()
{cout << "Jestem 1 klasa pochodna" << endl;}
};
//---------------------------------------------------------
class TPochodna2 : public TBazowa {
public:
/*virtual*/ void __fastcall pokazB()
{cout << "Jestem 2 klasa pochodna" << endl;}
};
//---------------------------------------------------------
242(29-05-06/14:07) D:\Roboczy Jarek\makiety poprawki i druku pdf\C++Builder Borland Developer Studio 2006. Kompendium programisty\
Rozdział 4. G Wczesne oraz późne wiązanie
243
void __fastcall pokazB(TBazowa &x) // odwołanie do klasy bazowej
{ x.pokazB();
return;
}//---------------------------------------------------------
int main()
{ TBazowa bazowa;
TPochodna1 pochodna1;
TPochodna2 pochodna2;
pokazB(bazowa); // wywołanie funkcji pokazB() klasy TBazowa pokazB(pochodna1); // wywołanie funkcji pokazB() klasy TPochodna1
pokazB(pochodna2); // wywołanie funkcji pokazB() klasy TPochodna2
cin.get();
return 0;
}//---------------------------------------------------------
Wskazówka
Bardzo często funkcje zawierające odwołania do klas polimorficznych mają (chociaż niekoniecznie) takie same nazwy, jak funkcje wirtualne względem danej klasy. Chociaż funkcje te mogą mieć takie same nazwy, nie należy utożsamiać ich z funkcjami przeładowanymi. Pomiędzy konstrukcją funkcji przeładowywanych i ponownym definiowaniem funkcji wirtualnych istnieją poważne różnice, np. prototypy funkcji wirtualnych muszą być identyczne, funkcje przeładowane zaś mają różną liczbę lub typ parametrów. Z tego powodu ponowne definiowanie funkcji wirtualnych nazywa się przykrywaniem lub nadpisywaniem funkcji.
Tematem poprzedniego podrozdziału były funkcje wirtualne, czyli funkcje deklarowane ze słowem kluczowym virtual. Z przedstawionych przykładów łatwo wywnioskujemy, iż wielką ich zaletą jest to, że są one odpowiednio przykrywane w klasach pochodnych. Jednak w języ-ku C++ słowo virtual posiada jeszcze jedno znaczenie, służy mianowicie do deklarowania tzw. wirtualnych klas bazowych.
Rozpatrzmy sytuację, w której potrzebujemy zdefiniować w programie pewną klasę bazową TBazowa, dwie klasy pochodne TPochodna1 i TPochodna2 dziedziczące po klasie bazowej i dodatkowo trzecią klasę pochodną TPochodna3, dziedziczącą elementy publiczne klas TPochodna1
i TPochodna2. W każdej z klas zdefiniujmy po jednej funkcji zwracającej pewną wartość całkowitą. Przyjęte założenia ilustruje rysunek 4.1 oraz listing 4.5.
D:\Roboczy Jarek\makiety poprawki i druku pdf\C++Builder Borland Developer Studio 2006. Kompendium programisty\04.doc (29-05-06/14:07)
243
244
C++Builder Borland Developer Studio 2006. Kompendium programisty
Rysunek 4.1. Idea poziomego dziedziczenia klas. Klasa TPochodna3 dziedziczy poziomo (wielokrotnie) po klasach TPochodna1 i TPochodna2
Listing 4.5. Kod głównego modułu Unit_R4_05.cpp projektu Projekt_R4_05.bdsproj wykorzystującego standardowe klasy bazowe
// Program nie zostanie skompilowany !
#include
#include
#pragma hdrstop
using namespace std;
class TBazowa {
public:
int i;
int __fastcall pokazB()
{cout << "Jestem klasa bazowa" << endl;
return i; }
};
//---------------------------------------------------------
class TPochodna1 : public TBazowa {
public:
int j;
int __fastcall pokazP1()
{cout << "Jestem 1 klasa pochodna" << endl;
return j;}
};
//---------------------------------------------------------