dynamic binding
Főnév
dynamic binding (tsz. dynamic bindings)
- (informatika) A dinamikus névkötés (dynamic binding) vagy késleltetett névkötés (late binding) azt jelenti, hogy egy függvényhez való kötés futásidőben (run-time) történik, nem pedig fordításkor. A C++ nyelvben ez akkor történik meg, ha egy függvény virtuális (
virtual
) kulcsszóval van ellátva. A dinamikus névkötést főként polimorfizmus és öröklődés esetén használjuk.
1. Miért fontos a dinamikus névkötés?
Normál esetben a C++ statikus névkötést (static binding) használ, ami azt jelenti, hogy a fordító már fordítási időben eldönti, hogy egy adott függvényhívás melyik függvényre vonatkozik. Azonban polimorfikus osztályoknál szükség lehet arra, hogy a program futásidőben döntsön arról, hogy egy adott függvényhívás melyik osztály verzióját hívja meg.
Példa statikus névkötésre (NEM megfelelő polimorfizmusnál):
#include <iostream>
using namespace std;
class Alaposztaly {
public:
void print() { // Nem virtuális függvény -> statikus névkötés
cout << "Alaposztaly print()" << endl;
}
};
class Leszarmazott : public Alaposztaly {
public:
void print() { // Nem virtuális -> statikus névkötés
cout << "Leszarmazott print()" << endl;
}
};
int main() {
Alaposztaly* obj = new Leszarmazott();
obj->print(); // Statikus névkötés miatt az Alaposztaly verziója hívódik meg
delete obj;
return 0;
}
Kimenet:
Alaposztaly print()
🔴 Hiba: Mivel a print()
függvény nem virtuális, a fordító statikus névkötést használ, és az Alaposztaly
verziója hívódik meg, annak ellenére, hogy az obj
egy Leszarmazott
objektumra mutat.
✅ Megoldás: Használjunk virtuális (virtual
) függvényeket, hogy a névkötés futásidőben történjen!
2. Dinamikus névkötés használata (virtual
kulcsszóval)
Ha egy függvény virtuális, akkor a hívás futásidőben dől el, attól függően, hogy a tényleges objektum milyen típusú.
Helyes példa dinamikus névkötésre:
#include <iostream>
using namespace std;
class Alaposztaly {
public:
virtual void print() { // Virtuális függvény -> dinamikus névkötés
cout << "Alaposztaly print()" << endl;
}
};
class Leszarmazott : public Alaposztaly {
public:
void print() override { // Dinamikus névkötés -> leszármazott verziója hívódik meg
cout << "Leszarmazott print()" << endl;
}
};
int main() {
Alaposztaly* obj = new Leszarmazott();
obj->print(); // Dinamikus névkötés miatt a Leszarmazott print() hívódik meg
delete obj;
return 0;
}
Kimenet:
Leszarmazott print()
✅ Miért működik? - Mivel a print()
virtuális (virtual
), a futásidőben dől el, hogy melyik osztály verziója hívódik meg. - A obj
egy Alaposztaly*
mutató, de egy Leszarmazott
objektumot mutat. - A vtable (virtuális táblázat) mechanizmusnak köszönhetően a megfelelő verzió (Leszarmazott::print()
) fut le.
3. Hogyan működik a dinamikus névkötés belsőleg?
A dinamikus névkötés a virtuális táblázaton (vtable) és a virtuális mutatón (vptr) alapul.
VTable (virtuális táblázat) működése
- Amikor egy osztály legalább egy virtuális függvényt tartalmaz, a fordító létrehoz egy vtable-t (virtuális függvénytáblát).
- Az osztály minden példánya kap egy vptr (virtuális mutató) nevű mutatót, amely a megfelelő vtable bejegyzésre mutat.
- Amikor egy virtuális függvényt meghívunk, a vptr alapján a megfelelő függvény futásidőben kerül kiválasztásra.
4. További példák dinamikus névkötésre
Több virtuális függvény
#include <iostream>
using namespace std;
class Alaposztaly {
public:
virtual void f1() { cout << "Alaposztaly f1" << endl; }
virtual void f2() { cout << "Alaposztaly f2" << endl; }
};
class Leszarmazott : public Alaposztaly {
public:
void f1() override { cout << "Leszarmazott f1" << endl; } // Felülírva
void f2() override { cout << "Leszarmazott f2" << endl; } // Felülírva
};
int main() {
Alaposztaly* obj = new Leszarmazott();
obj->f1(); // Leszarmazott f1
obj->f2(); // Leszarmazott f2
delete obj;
return 0;
}
✅ A futásidőben dől el, hogy a Leszarmazott
osztály függvényei hívódnak meg.
Virtuális destruktorok és dinamikus névkötés
Ha egy osztály virtuális függvényeket tartalmaz, a destruktora is legyen virtuális, különben memória-szivárgás történhet!
#include <iostream>
using namespace std;
class Alaposztaly {
public:
virtual ~Alaposztaly() { cout << "Alaposztaly destruktor" << endl; }
};
class Leszarmazott : public Alaposztaly {
public:
~Leszarmazott() { cout << "Leszarmazott destruktor" << endl; }
};
int main() {
Alaposztaly* obj = new Leszarmazott();
delete obj; // Helyesen hívja a Leszarmazott destruktorát
return 0;
}
Kimenet:
Leszarmazott destruktor Alaposztaly destruktor
✅ A ~Alaposztaly()
virtuális, így a megfelelő destruktorok meghívódnak.
5. Statikus vs. Dinamikus névkötés összehasonlítása
Típus | Időpont | Használat | Példa |
---|---|---|---|
Statikus névkötés (Static Binding) | Fordítási időben | Normál függvények, statikus változók | Nem virtuális osztályfüggvények |
Dinamikus névkötés (Dynamic Binding) | Futási időben | Virtuális függvények, polimorfizmus | Virtuális függvények (virtual )
|
6. Összegzés
✅ A dinamikus névkötés (dynamic binding
) azt jelenti, hogy a függvényhívás futásidőben dől el.
✅ Virtuális (virtual
) függvények használatával érhető el.
✅ A polimorfizmus megvalósításához elengedhetetlen.
✅ A virtuális táblázat (vtable) és virtuális mutató (vptr) mechanizmuson alapul.
- dynamic binding - Szótár.net (en-hu)
- dynamic binding - Sztaki (en-hu)
- dynamic binding - Merriam–Webster
- dynamic binding - Cambridge
- dynamic binding - WordNet
- dynamic binding - Яндекс (en-ru)
- dynamic binding - Google (en-hu)
- dynamic binding - Wikidata
- dynamic binding - Wikipédia (angol)