Sunday, 13 July 2014

Virtual Functions-- Facts

1.Whenever virtual function is called using base class reference or pointer it cannot be inlined (because call is resolved at runtime), but whenever called using the object (without reference or pointer) of that class, can be inlined because compiler knows the exact class of the object at compile time.
2.#include<iostream>
using namespace std;
class Base {
public:
    virtual int fun(int i) { cout << "Base::fun(int i) called"; }
};
class Derived: public Base {
private:
    int fun(int x)   { cout << "Derived::fun(int x) called"; }
};
int main()
{
    Base *ptr = new Derived;
    ptr->fun(10);
    return 0;
}
Output:
 Derived::fun(int x) called 
In the above program, private function “Derived::fun(int )” is being called through a base class pointer, the program works fine because fun() is public in base class. Access specifiers are checked at compile time and fun() is public in base class. At run time, only the function corresponding to the pointed object is called and access specifier is not checked. So a private function of derived class is being called through a pointer of base class.           
3. Virtual functions can be private and can be overridden by the derived class. For example, the following program compiles and runs fine.
#include<iostream>
using namespace std;
class Derived;
class Base {
private:
    virtual void fun() { cout << "Base Fun"; }
friend int main();
};
class Derived: public Base {
public:
    void fun() { cout << "Derived Fun"; }
};
int main()
{
   Base *ptr = new Derived;
   ptr->fun();
   return 0;
}
Output:

Derived fun()

4.Deleting a derived class object using a pointer to a base class that has a non-virtual 
destructor results in undefined behavior. To correct thissituation, the base class should be 
defined with a virtual destructor. Making base class destructor virtual guarantees that the 
object of derived class is destructed properly, i.e., both base class and derived  class 
destructors are called.

5. How does compiler do this magic of late resolution?
Compiler maintains two things to this magic: virtualFuns vtable: A table of function pointers. It is maintained per class. vptr: A pointer to vtable. It is maintained per object (See this for an example).
Compiler adds additional code at two places to maintain and use vptr. 1) Code in every constructor. This code sets vptr of the object being created. This code sets vptr to point to vtable of the class. 2) Code with polymorphic function call . Wherever a polymorphic call is made, compiler inserts code to first look for vptr using base class pointer or reference (In the above example, since pointed or referred object is of derived type, vptr of derived class is accessed). Once vptr is fetched, vtable of derived class can be accessed. Using vtable, address of derived derived class function show() is accessed and called.

References:
1. http://www.geeksforgeeks.org/virtual-functions-and-runtime-polymorphism-in-c-set-1-introduction/ 
2. http://www.geeksforgeeks.org/g-fact-37/
3. http://www.geeksforgeeks.org/can-virtual-functions-be-private-in-c/
4. http://www.geeksforgeeks.org/what-happens-when-more-restrictive-access-is-given-in-a-derived-class-method-in-c/
5. http://www.geeksforgeeks.org/inline-virtual-function/
 

No comments:

Post a Comment