Ugrás a tartalomhoz

dynamic binding

A Wikiszótárból, a nyitott szótárból

Főnév

dynamic binding (tsz. dynamic bindings)

  1. (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.