Search code examples
c++ooppolymorphismdynamic-bindingstatic-binding

Cases of static and dynamic binding in C++


The following code has 4 classes: Base1, Derived1 (derived from Base1), Base2, Derived2 (derived from Base2). Both base classes have integer data1 and display_data() functions. Both derived classes have integers data1 and data2, and display_data() functions.

I tried 4 cases in my code, which can be seen in the main function. I am unable to figure which of these is a case of static binding and which is dynamic. I need some help here. I would also like to know, which of these cases can be considered as "function overriding".

CODE:

#include <iostream>
using namespace std;

class Base1{
protected:
    int data1;

public:
    Base1(int idata1 = 0) {
        data1 = idata1;
    }

    void display_data() {
        cout << "Base1: " << data1 << endl;
    }
};

class Derived1 : public Base1 {
protected:
    int data2;

public:
    Derived1(int idata1 = 0, int idata2 = 0) {
        data1 = idata1;
        data2 = idata2;
    }

    void display_data() {
        cout << "Derived1: " << data1 << ' ' << data2 << endl;
    }
};


class Base2 {
protected:
    int data1;

public:
    Base2(int idata1 = 0) {
        data1 = idata1;
    }

    virtual void display_data() {
        cout << "Base2: " << data1 << endl;
    }
};

class Derived2 : public Base2 {
protected:
    int data2;

public:
    Derived2(int idata1 = 0, int idata2 = 0) {
        data1 = idata1;
        data2 = idata2;
    }

    void display_data() {
        cout << "Derived2: " << data1 << ' ' << data2 << endl;
    }
};

int main()
{
    // case 1
    Derived1 d1(1, 10);
    d1.display_data();

    // case 2
    Base1* d2 = new Derived1(2, 20);
    d2->display_data();

    // case 3
    Derived2 d3(3, 30);
    d3.display_data();

    // case 4
    Base2* d4 = new Derived2(4, 40);
    d4->display_data();

    return 0;
}

OUPUT:

Derived1: 1 10
Base1: 2
Derived2: 3 30
Derived2: 4 40

Solution

  • Here is my attempt to explain it in a simple way :)

    Static binding occurs when an object is associated with a member function based on the static type of the object (understand the type of its class).

    Dynamic binding occurs when a pointer or reference is associated with a member function based on the dynamic type of the object (understand the instance of the variable at runtime).

    Before reading on: Dynamic binding works only with pointers or references and with virtual functions for the base class.

    The first call is a static binding (also called early binding)because everything needed to call the function is known at compile-time.

        Derived1 d1(1, 10);
        d1.display_data();
    

    You know that the d1 instance is an automatic variable of type Derived1 and then it will call the method Derived1::display_data().

    • The first conditions is not OK: d1 is not a pointer nor is it a reference.
    • the second conditions is not OK: Derived1::display_data is not virtual.

    For the second call

        Base1* d2 = new Derived1(2, 20);
        d2->display_data();
    

    We see that the declared type of the variable d2 is of Base1 but the instance is of Derived1 (it is correct because of inheritance thus Derived1 is a Base1 class). But you do not know yet at if the display_data method that it will call is the one from Base1::display_data o the one from Derived1::display_data.

    • The first conditions is OK because we have the d2 of type pointer Base1*.
    • The second condition is not OK because the Base1::display_data is not virtual. Thus it is still a static binding then the function that will be called is the one with the declared type, thus the code will call Base1::display_data

    For the third call

        // case 3
        Derived2 d3(3, 30);
        d3.display_data();
    

    This will result in a static binding then calling the Derived3::display_data

    • The first conditions is not OK: d3 is not a pointer nor is it a reference.
    • the second conditions is OK: Derived2::display_data is virtual.

    For the fourth call

        Base2* d4 = new Derived2(4, 40);
        d4->display_data();
    

    This time it is a dynamic binding.

    • The first conditions is OK: d4 is a pointer.
    • the second conditions is OK: Derived2::display_data is virtual. thus instead of calling the method from the declared type base2, it will call the method from the declared instance at runtime Derived2::display_data