× back Virtual function Early binding and late binding Pure virtual function Abstract classes Runtime and compile-time polymorphism
Next Topic → ← Previous Topic

Virtual function

Virtual function

Let's resolve the problem

                   
#include <iostream>
using namespace std;
class base_class
{
public:
    virtual void show()
    {
        cout << "we are in base class yeah";
    }
};

class derived_class : public base_class
{
public:
    void show()
    {
        cout << "we are in derived class yeah";
    }
};

int main()
{
    base_class *basePtr;
    derived_class objOfDerivedC;
    basePtr = &objOfDerivedC;
    basePtr->show();
    return 0;
}
                   
               

Output ↓

                
we are in derived class yeah
                
            

Early binding & late binding

Early binding (static binding)

  • Early binding occurs when the function call is resolved at compile-time.
  • The compiler determines which function to call based on the static type of the object. It is also known as static binding because the binding between the function call and the function implementation is done before the program is executed.

Program to demonstrate early binding

                   
#include <iostream>
using namespace std;

class Shape
{
public:
    void draw()
    {
        cout << "Drawing Shape." << endl;
    }
};

class Circle : public Shape
{
public:
    void draw()
    {
        cout << "Drawing Circle." << endl;
    }
};

int main()
{
    Shape shape;
    Circle circle;

    Shape *shapePtr = &shape;
    shapePtr->draw(); // Calls Shape's draw() function (early binding)

    shapePtr = &circle;
    shapePtr->draw(); // Calls Shape's draw() function (early binding)

    return 0;
}
                   
               
  • Just because we are not using virutal function this becomes example of early binding.

Late binding (Dynamic binding)

  • Late binding occurs when the function call is resolved at runtime. The compiler defers the binding of the function call to the actual object until runtime. It is also known as dynamic binding or virtual binding.
                       
#include <iostream>
using namespace std;
class Shape
{
public:
    virtual void draw()
    {
        cout << "Drawing Shape." << endl;
    }
};

class Circle : public Shape
{
public:
    void draw()
    {
        cout << "Drawing Circle." << endl;
    }
};

int main()
{
    Shape *shapePtr;
    Shape shape;
    Circle circle;

    shapePtr = &shape;
    shapePtr->draw(); // Calls Shape's draw() function (late binding)

    shapePtr = &circle;
    shapePtr->draw(); // Calls Circle's draw() function (late binding)

    return 0;
}
                       
                   

Pure virtual functions

Example ↓

                   
#include <iostream>
using namespace std;
class Shape
{
public:
    virtual void draw() = 0; // Pure virtual function
};

class Circle : public Shape
{
public:
    void draw() override // overide is keyword which ensure we are overriding function in derived class from base class.
    {
        cout << "Drawing Circle." << endl;
    }
};

class Rectangle : public Shape
{
public:
    void draw() override
    {
        cout << "Drawing Rectangle." << endl;
    }
};

int main()
{
    Circle circle;
    Rectangle rectangle;

    circle.draw();    // Calls Circle's draw() function
    rectangle.draw(); // Calls Rectangle's draw() function

    return 0;
}
                   
               

Abstract classes

Example program ↓

                   
#include <iostream>
using namespace std;
class Shape // abstract class
{
public:
    virtual void draw() = 0; // Pure virtual function
};

class Circle : public Shape
{
public:
    void draw() override
    {
        cout << "Drawing Circle." << endl;
    }
};

class Rectangle : public Shape
{
public:
    void draw() override
    {
        cout << "Drawing Rectangle." << endl;
    }
};

int main()
{
    Circle circle;
    Rectangle rectangle;

    circle.draw();
    rectangle.draw();

    return 0;
}
                   
               

How Runtime polymorphism and Compile-time polymorphism is related to early and late binding??

Runtime polymorphism

  • Runtime polymorphism, also known as dynamic polymorphism, is achieved through the use of virtual functions.
  • It allows the selection of the appropriate function implementation at runtime based on the actual object type. This is possible because virtual functions are resolved dynamically (late binding).
  • The binding of the function call to its implementation occurs at runtime, depending on the type of the object being referenced or pointed to.

Compile-time Polymorphism

  • Compile-time polymorphism, also known as static polymorphism, is achieved through function overloading and templates. In function overloading, multiple functions with the same name but different parameter lists can be defined. The appropriate function is selected based on the static types of the arguments at compile time.