| Časová náročnost: 15 minut |
Virtuální funkce je členská funkce, která je deklarována v rámci základní třídy a je
redefinována odvozenou třídou. Aby byla funkce považována za virtuální je nutné uvést před jejím jménem klíčové slovo
virtual. Při dědění třídy, která obsahuje virtuální funkci, si odvozená třída virtuální funkci redefinuje dle sebe. Když je virtuální funkce redefinována odvozenou třídou není již klíčové slovo
virtual nutné.
Virtuální funkce může být volána jako jakákoliv jiná členská funkce. Když ukazatel základní třídy ukazuje na odvozený objekt, který obsahuje virtuální funkci, a tato virtuální funkce je volána prostřednictvím ukazatele, pak se na základě
typu objektu odkazovaného ukazatelem určí a to za
běhu programu, která verze virtuální funkce bude spuštěna.
Tímto způsobem se dociluje polymorfismu za běhu programu. Následně se třídě, která definuje virtuální funkci říká
polymorfická třída.
V následujícím příkladu si ukážeme doposud probranou teorii virtuálních funkcí.
| Příklad 9.1. |
|
#include <iostream.h>
class base {
public:
int i;
base(int x) { i = x; }
virtual void func()
{
cout << "Verze func() ze tridy base: ";
cout << i << '\n';
}
};
class derived1 : public base {
public:
derived1(int x) : base(x) {}
void func()
{
cout << "Verze func() ze tridy derived1: ";
cout << i*i << '\n';
}
};
class derived2 : public base {
public:
derived2(int x) : base(x) {}
void func()
{
cout << "Verze func() ze tridy derived2: ";
cout << i+i << '\n';
}
};
int main()
{
base *p;
base ob(10);
derived1 d_ob1(10);
derived2 d_ob2(10);
p = &ob;
p->func(); // func() tridy base
p = &d_ob1;
p->func(); // func() tridy derived1
p = &d_ob2;
p->func(); // func() tridy derived2
return 0;
}
|
Pokud odvozená třída nepřehodnotí virtuální funkci, pak je použita funkce definovaná v základní třídě.
| Příklad 9.2. |
|
#include <iostream.h>
class base {
public:
int i;
base(int x) { i = x; }
virtual void func()
{
cout << "Verze func() ze tridy base: ";
cout << i << '\n';
}
};
class derived1 : public base {
public:
derived1(int x) : base(x) {}
void func()
{
cout << "Verze func() ze tridy derived1: ";
cout << i*i << '\n';
}
};
class derived2 : public base {
public:
derived2(int x) : base(x) {}
};
int main()
{
base *p;
base ob(10);
derived1 d_ob1(10);
derived2 d_ob2(10);
p = &ob;
p->func(); // func() tridy base
p = &d_ob1;
p->func(); // func() tridy derived1
p = &d_ob2;
p->func(); // func() tridy base
return 0;
}
|
Může se stát, že ikdyž je virtuální funkce definována v základní třídě, tak nemusí provádět smysluplné operace. Někdy prostě jenom definuje základní sadu členských funkcí a proměnných, které si pak odvozené funkce upraví.
|
Jazyk C++ proto podporuje tzv. čistě virtuální funkce. Čistě virtuální funkce nemají definici vztaženou k základní třídě. Je v ní zahrnut pouze prototyp s následující syntaxí:
virtual typ jméno-funkce(seznam-argumentů) = 0;
Tato syntaxe říká překladači, že vzhledem k základní třídě nemá funkce tělo. Pokud je virtuální funkce definována jako čistá, pak to každou odvozenou třídu nutí, aby ji přehodnotila. Jestliže to odvozená třída neudělá, ohlásí se chyba překladu.
Pokud třída obsahuje nejméně jednu čistě virtuální funkci, pak je na ni odkazováno jako na abstraktní třídu. Abstraktní třídy tedy existují proto, aby mohly být děděny.
Následující příkaz nám ukazuje použití čisté virtuální funkce. Program vypočte obsah čtyřúhelníka a trojúhelníka na základě děděné čisté virtuální funkce.
|
| Příklad 9.3. |
|
#include <iostream.h>
class area {
double dim1, dim2; // rozmery
public:
void setarea(double d1, double d2)
{
dim1 = d1;
dim2 = d2;
}
void getdim(double &d1, double &d2)
{
d1 = dim1;
d2 = dim2;
}
virtual double getarea() = 0; // cista virtualni funkce
};
class rectangle : public area {
public:
double getarea()
{
double d1, d2;
getdim(d1, d2);
return d1 * d2;
}
};
class triangle : public area {
public:
double getarea()
{
double d1, d2;
getdim(d1, d2);
return 0.5 * d1 * d2;
}
};
int main()
{
area *p;
rectangle r;
triangle t;
r.setarea(3.3, 4.5);
t.setarea(4.0, 5.0);
p = &r;
cout << "Obsah ctyruhelnika je: " << p->getarea() << '\n';
p = &t;
cout << "Obsah trojuhelnika je: " << p->getarea() << '\n';
return 0;
}
|
| Flashová animace |
|
Kliknutím na ikonu spustíte animaci.
|