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.
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.
Pokud vynecháme klíčová slova virtual u metod print a distance ve třídě Basic
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.
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