Introduction
Polymorphism is the way of achieving a layer of separation of interfaces from implementation, or in other words, decoupling what from how. It improves code organization, readability and extensible program.
Connecting a function call to a function body is called as binding. In C++, there are two types of binding: namely static (early) binding and dynamic (late/run-time) binding. If binding happens during compilation/linking time (that is, before running), then it's called as early binding. Binding happening during runtime is called late binding, which is
achieved through virtual functions.
Virtual Functions
Typically compiler creates a single table called Virtual Table (VTABLE) for each class that has virtual functions. VTABLE will contain information of all virtual functions
(address and sometimes offset) and RTTI information. Compiler places the addresses of virtual functions for that particular class in the VTABLE. When we instantiate a class with virtual function, compiler secretly places a pointer in that object called VPTR which points to the VTABLE for that class. All objects of same class will have same VPTR. This is because, VTABLE''s are created per class basis during compilation time.
When virtual function call is made through a base class pointer, the compiler quietly inserts code to fetch the VPTR and look up the function address in the VTABLE, calling the correct function and causing late binding to take place.
In C and C++, arguments are pushed onto stack from right to left, while calling a function (mapping actual parameters to actual arguments). This order is required to support
variable argument lists. When a non-static function is called from a object or pointer/reference to object, compiler will push the pointer to object also on to stack. This is because, compiler generated code for that function will take object pointer as the first parameter implicitly, which is referenced as “this” pointer.
Example:
void Sample::Foo(int aVal);
will be converted into something like this by the compiler:
void Sample_Foo(Sample* this, int aVal);
When a virtual function is called on a pointer/reference of object, following code will be inserted to support late binding.
class Base {
public:
virtual void Fun1();
virtual void Fun2(int );
virtual void Fun3(int, float);
};
Void SomeFunction(Base* aBase){
aBase->Fun3(1, 2.5);
}
aBase->Fun3(1, 2.5) will be replaced with something like this by compiler:
push 2.5 //Push right most parameter, 2.5
push 1 //Push next parameter, 1
push si //Push “this” pointer, assuming SI register holds aBase
mov bx, word ptr[si] //get VPTR (pointer of to VTABLE) using “this” address
call word ptr[bx+4] //call Fun3 using VTABLE indexing
add sp, 12 //Clear the stack by moving stack pointer with 12 bytes
Compiler will have its own (static) ordering for all virtual functions. Its determined by the way its been specified in base class. Even if the derived class overrides them in different order, the order will be fixed. So, Fun1 will be at first offset, then Fun2 and then Fun3. So bx+4 is for fetching address of Fun3. Compiler will have all these housekeeping data and activity, so programmer does not have to break their head for this. All these are the overhead of virtual functions.
Pure Virtual Functions
Pure virtual function is one, for which it's not required to have definition, but the class, which derives the class, should override it. A virtual function can be inline and the inline request may be served, if it's called on an object, but not when it's called on reference or pointer to the class. But, a pure virtual function can't be inline, because pure virtual means, we wont give implementation to that function and that class is Abstract Base Class (ABC), which means we can't instantiate that class. So there is no meaning in making pure virtual function, as inline for which there is no definition with that class.
Even though we specify a function as pure virtual in a class, we can give definition/implementation to that function in that class and at the same time, all derived
class should give implementation. This is helpful when we want to make a base class function as pure virtual without disturbing the existing code. This gives a way to find out
all classes that don't override that virtual function.
We can have a destructor as pure virtual, but we should give definition for that. But the classes deriving that may not override it!
Calling virtual function from non-virtual function
In some scenario, where there is exists a common algorithm for all derived class, then it's a better idea to move it into public section of base and to make it as non-virtual. That is, moving general concrete algorithm to Base class (generally, it will be ABC). There are times at which, this algorithm will make use of some small piece of specialized code that will be derived class specific. In such cases, keep that code in some virtual function and make that function as pure virtual in Base and keep in protected section of base. All derived class will give their specific implementation for that function.
class Shape{
protected:
virtual float Area() = 0;
public:
void SomeAlgorithm() {
//Do some computation
area = this->Area();
//more computation follows
}
};
class Square : public Shape{
float iSide;
protected:
virtual float Area(){
return (iSide*iSide);
}
};
class Circle : public Shape{
float iRadius;
protected:
virtual float Area(){
return (PI* iRadius * iRadius);
}
};
Base Constructor and destructor calling virtual functions
Dynamic binding or virtual mechanism happens only on fully constructed object and it has obvious reason for this behavior. What happens when a base constructor calls a virtual function? And the answer will be, calling virtual function in base constructor will be statically bind during compilation time. Its because, while executing Base's constructor, the “this” object is not yet of type Derived as Derived part is not yet constructed completely; it's still of type Base. That's why call to virtual function within Base constructor binds to Base's (local) virtual function.
Calling virtual function from Base's destructor will have same behavior as Derived part of object is destroyed already, so only local function will be called, which is bind to Base's (local) virtual function.
A class's constructor and destructor can't call it's own pure-virtual functions. But some other functions of same class can do so. All these behavior is to protect us from potential, serious, subtle bug of accessing non-static data member of Derived that are not yet initialized/allocated or destroyed already.
Polymorphism
Polymorphism
Polymorphism
"In C and C++, arguments are pushed onto stack from right to left, while calling a function (mapping actual parameters to actual arguments). This order is required to support variable argument lists. "
IMHO, I think the key to support variable argument lists is that the caller (not the callee) takes charge of cleaning the stack, instead of the push-stack order of the arguments.