Skip to main content
Engineering LibreTexts

5.2: Virtual Functions in C++

  • Page ID
    37780
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    A virtual function is a member function which is declared within a base class and is re-defined(Overriden) by a derived class. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class’s version of the function.

    • Virtual functions ensure that the correct function is called for an object, regardless of the type of reference (or pointer) used for function call.
    • They are mainly used to achieve Runtime polymorphism
    • Functions are declared with a virtual keyword in base class.
    • The resolving of function call is done at Run-time.

    Rules for Virtual Functions

    1. Virtual functions cannot be static and also cannot be a friend function of another class.
    2. Virtual functions should be accessed using pointer or reference of base class type to achieve run time polymorphism.
    3. The prototype of virtual functions should be same in base as well as derived class.
    4. They are always defined in base class and overridden in derived class. It is not mandatory for derived class to override (or re-define the virtual function), in that case base class version of function is used.
    5. A class may have virtual destructor but it cannot have a virtual constructor.

    Compile-time(early binding) VS run-time(late binding) behavior of Virtual Functions

    Consider the following simple program showing run-time behavior of virtual functions.

    // C++ program for function overriding 
    #include <iostream> 
    using namespace std; 
    
    class base 
    { 
        public: 
            virtual void print () 
            { 
                cout<< "print in base class" <<endl; 
            } 
    
            void show () 
            { 
                cout<< "show in base class" <<endl; 
            } 
    }; 
    
    class derived:public base 
    { 
        public: 
            // print() is already virtual function in 
            // derived class, we could have declared
            // it as virtual void print() explicitly 
            void print () 
            {
                cout<< "print in derived class" <<endl; 
            } 
    
            void show () 
            { 
                cout<< "show in derived class" <<endl; 
            } 
    }; 
    
    //main function 
    int main() 
    { 
        base *bptr; 
        derived d; 
        bptr = &d; 
        
        //virtual function, bound at runtime (Runtime polymorphism) 
        bptr->print(); 
        
        // Non-virtual function, bound at compile time 
        bptr->show(); 
    
        return 0; 
    } 
    

    The idea is that virtual functions are called according to the type of the object instance pointed to or referenced, not according to the type of the pointer or reference. This means that in this example, bptr is pointing at a derived type, &d, so therefore at execution time we run the derived class print() method, because the base class print() method is virtual. Since the base class show() method is NOT virtual, then we run the base class show() method.

    Output:

    print in derived class
    show in base class
    

    Runtime polymorphism is achieved only through a pointer (or reference) of base class type. Also, a base class pointer can point to the objects of base class as well as to the objects of derived class. In above code, base class pointer ‘bptr’ contains the address of object ‘d’ of derived class.

    Late binding(Runtime) is done in accordance with the content of pointer (i.e. location pointed to by pointer) and Early binding(Compile time) is done according to the type of pointer, since print() function is declared with virtual keyword so it will be bound at run-time (output is print derived class as pointer is pointing to object of derived class ) and show() is non-virtual so it will be bound during compile time(output is show base class as pointer is of base type ).

    NOTE: If we have created a virtual function in the base class and it is being overridden in the derived class then we don’t need virtual keyword in the derived class, functions are automatically considered as virtual functions in the derived class.

    Working of virtual functions(concept of VTABLE and VPTR)

    As discussed here, If a class contains a virtual function then compiler itself does two things:

    1. If object of that class is created then a virtual pointer(VPTR) is inserted as a data member of the class to point to VTABLE of that class. For each new object created, a new virtual pointer is inserted as a data member of that class.
    2. Irrespective of object is created or not, a static array of function pointer called VTABLE where each cell contains the address of each virtual function contained in that class.

    Consider the example below:
    Image showing a pictorial representation of a virtual function

     

    // CPP program to illustrate 
    // working of Virtual Functions 
    #include <iostream> 
    using namespace std; 
    
    class base { 
        public: 
            void fun_1() { cout << "base-1\n"; } 
            virtual void fun_2() { cout << "base-2\n"; } 
            virtual void fun_3() { cout << "base-3\n"; } 
            virtual void fun_4() { cout << "base-4\n"; } 
    }; 
    
    class derived : public base { 
        public: 
            void fun_1() { cout << "derived-1\n"; } 
            void fun_2() { cout << "derived-2\n"; } 
            void fun_4(int x) { cout << "derived-4\n"; } 
    }; 
    
    int main() 
    { 
        base* p; 
        derived obj1; 
        p = &obj1; 
    
        // Early binding because fun1() is non-virtual 
        // in base 
        p->fun_1(); 
    
        // Late binding (RTP) 
        p->fun_2(); 
    
        // Late binding (RTP) 
        p->fun_3(); 
    
        // Late binding (RTP) 
        p->fun_4(); 
    
        // The following is early binding but this
        // function call is illegal(produces error)
        // because pointer is of base type and
        // function is of derived class 
        // p->fun_4(5); 
    } 
    
    

    Output:

    base-1
    derived-2
    base-3
    base-4
    

    Initially, we create a pointer of type base class and initialize it with the address of the derived class object. When we create an object of the derived class, the compiler creates a pointer as a data member of the class containing the address of VTABLE of the derived class.

    Similar concept of Late and Early Binding is used as in above example. For fun_1() function call, base class version of function is called, fun_2() is overridden in derived class so derived class version is called, fun_3() is not overridden in derived class and is virtual function so base class version is called, similarly fun_4() is not overridden so base class version is called.

    NOTE: fun_4(int) in derived class is different from virtual function fun_4() in base class as prototype of both the function is different.

    Adapted from:
    "Virtual Function in C++" by Yash Singla, Geeks for Geeks is licensed under CC BY-SA 4.0


    5.2: Virtual Functions in C++ is shared under a not declared license and was authored, remixed, and/or curated by LibreTexts.

    • Was this article helpful?