Table of Contents

Tabulka virtuálních metod

Třídy, které mají virtuální metody, obsahují ukazatel na tabulku virtuálních metod.
Tabulka má pro každou virtuální metodu jednu řádku s ukazatelem na funkci implementující danu metodu.
Každé virtuální metodě překladač přiřadí číslo řádky v tabulce virtuálních metod.

Pokud vytvoříme více instancí téhož typu obsahují všechny instance ukzatel na stále stejnou tabulku virtuálních metod.
( A pokud máme více virtuálních metod, ušetříme místo v paměti, jednotlivé instance obsahují jeden ukazatel na tabulku místo několika ukazatelů na funkce, které by odpovídaly implementaci z předešlé kapitoly.)

Při volání virtuální metody se v instanci nalezne ukazatel na tabulku, v tabulce použije řádku odpovídající dané metodě a zde nalezene ukazatel na funkci, kterou zavolá.
( Při volání virtuální metod nesmí být ukazetel na instanci roven nullptr, jinak by nešlo nalézt tabulku virtuálních metod. )

V následujícím příkladu jsou dvě třídy a několik virtuálních metod.

class Basic
{
public:
     int x, y;
public :
     virtual void print () { cout << "Basic (" << x << ", " << y << ")" << endl; }
     virtual int  distance () { return sqrt (x*x +y*y); }
     virtual void scale (int c) { x = x * c; y *=c; }
};
 
class Component : public Basic
{
public:
     int z;
public :
     virtual void print () { cout << "Component (" << x << ", " << y << "," << z << ")" << endl; }
     virtual int  distance () { return sqrt (x*x +y*y + z*z); }
     virtual void move (int dx, int dy, int dz) { x += dx; y += dy; z += dz; }
};
Basic * b = new Basic;
Component * c = new Component;
Basic * u = c;

Proměnné x, y a z jsou poněkud nestandardně veřejně přístupné (public:)
K těmto proměnným můžeme přistupovat pomocí b→x, u→y nebo c→z
K proměnné z se nedostaneme pomocí ukazatele na Basic, tedy u→z nelze použít.

Vynechání některých klíčových slov virtual v odvozené třídě

Pokud vynecháme klíčové slovo virtual u metod print a distance ve třídě Component, program se bude chovat stejně, metody jsou již deklarovány jako virtální ve tříde Basic.

Vynechání některých klíčových slov virtual v základní třídě

Pokud vynecháme klíčová slova virtual u metod print a distance ve třídě Basic

Vynechání všech klíčových slov virtual v základní třídě

Pokud vynecháme klíčová slova virtual u všech metod ve třídě Basic,
třída nebude obsahovat ukazatel na tabulku virtuálních metod

Pokud odvozená třída Component stále bude mít virtuální metody,
překladač nejspíše ve třídě komponent nejprve umístí proměnné x a y, aby třída Component začínanala stejně třída Basic,
a ukazatele na instance odvozené třídy Component se daly přiřadit i do proměnných typu ukazatele na Basic (např. u = c;)

Za proměnné x a y nejspíše bude umístěn ukazatel na tabulku virtuálních metod a až za ním bude proměnná z.

Přetypování dynamic_cast

přetypování dynamic_cast

Proměnnou typu ukazatel na základní třídu nemůžeme přiřadit do proměnné typu ukazatel na odvozenou třídu.

   Basic * b = new Basic;
   Component * v = b;

Je zřejmé, že objekt typu Basic nemá proměnnou z a metodu move, a proto nelze přiřadit v = b;

Pokud v proměnné typu Basic* byl uložen objekt typu Component, potom by bylo možné objekt uložit do proměné typu Component*.
Ovšem překladač nám stejně přiřazení nedovolí. Z hlediska překladače je přířazení ukazatele na Basic do ukazatele na Component potenciálně nebezpečné.

   Item * c  = new Component;
   Basic * u = c;
   Component * v = u;  /* překladač ohlásí chybu */

Konstrukce dynamic_cast umožňuje přetypování ukazatele na základní třídu na ukazatel na odvozenou třídu

   Basic * u;
   Component * v = dynamic_cast < Component * > (u);

Pokud parametr v kulatých závorkách za běhu programu nebude skutečně typu uvedeného v < > závorkách, bude výsledkem nullptr