virtual method table (tsz. virtual method tables)
Amikor egy osztály tartalmaz virtuális metódusokat (pl. C++-ban a virtual
kulcsszóval jelöltek), a fordító létrehoz egy táblázatot (a VMT-t), amely a virtuális metódusokra mutató függvénymutatókat tartalmazza. Az egyes osztálypéldányok tartalmaznak egy rejtett mutatót erre a táblázatra, így a megfelelő metódus meghívása futásidőben dől el.
Vegyünk egy példát egy alaposztállyal és egy belőle származtatott osztállyal:
#include <iostream>
class Base {
public:
virtual void speak() {
std::cout << "Base says hello!" << std::endl;
}
};
class Derived : public Base {
public:
void speak() override {
std::cout << "Derived says hello!" << std::endl;
}
};
int main() {
Base* obj = new Derived();
obj->speak(); // "Derived says hello!" fut le, nem "Base says hello!"
delete obj;
return 0;
}
Base
osztály tartalmaz egy virtuális függvényt (speak
).Derived
osztály ezt a függvényt felülírja.Base*
mutató egy Derived
objektumra mutat, és meghívjuk a speak()
metódust, akkor a Derived osztály implementációja fog lefutni, nem a Base osztályé.
Ha elképzeljük a memóriaszerkezetet, akkor egy Base
és Derived
osztály példányai így néznének ki:
Base vtable: +-----------------+ | speak() -> Base::speak | +-----------------+ Derived vtable: +-----------------+ | speak() -> Derived::speak | +-----------------+
Az objektum egy mutatót tartalmaz a saját osztályának VMT-jére:
obj (Base*) -> ----> Derived vtable speak() -> Derived::speak
A VMT nem az egyetlen módszer a dinamikus polimorfizmus megvalósítására. Néhány alternatíva: - Függvénymutatók: Egy struktúrában vagy osztályban explicit függvénymutatókat is használhatunk, de ezek kevésbé átláthatók. - Template-ek (generikus programozás): A sablonok lehetővé teszik a statikus polimorfizmust, ami gyorsabb, de nem mindig alkalmas az OOP struktúrákhoz. - Statikus polimorfizmus (CRTP - Curiously Recurring Template Pattern): Egy alternatív megközelítés, amely fordítási időben oldja meg a függvényhívásokat.
A virtuális metódustábla egy hatékony mechanizmus az objektum-orientált programozásban a dinamikus metódushívások megvalósítására. Bár némi teljesítményhátránnyal jár, elengedhetetlen a polimorfizmus és az öröklődés helyes működéséhez. A legtöbb modern programozási nyelv (C++, Java, C#, stb.) valamilyen formában használja ezt a mechanizmust, hogy dinamikusan felülírt metódusokat lehessen kezelni.