Tuesday, June 23, 2009

TRICKY WAYS OF FUNCTION OVERLOADING

Most of the guys knew about Function Overloading – declaring more than one functions of the same name, it will differ in number of parameters or type of parameters but not depends on return type. For example,


int add(int a, int b)
{
    return (a+b);
}

float add(float a, float b)
{
    return (a+b);
}


Let’s invoke these functions:



    add(5+6); // invokes int-version of add function


    add(5.7+6.8) // invokes float-version of add function



As you can see that which version of add-function is going to be invoked depends on the parameters a caller passed. So one can invokes different versions of methods using same name that can give different functionality – that is nothing but implementation of Polymorphism (static Polymorphism, as function calls are resolved during compile time).

Now we will look into other ways of function overloading. To explain it properly, consider following example:


class CTest
{
public:

    int add(int a, int b)
    {
        cout<<"CTest::add(pass-by-value version)";
        return (a+b);
    }
    int add(int *a, int *b)
    {
        cout<<"CTest::add(pass-by-pointer version
        return (*a + *b);
    }


    void display()
    {
        cout<<"CTest::display(non-const version)";
    }
    void display() const
    {
        cout<<"CTest::display(const version)";
    }

};


Here, class CTest defines two versions of add() function as:


int add(int a, int b) – accepts pass-by-value parameters
int add(int *a, int *b) – accepts pass-by-pointer parameters



Both add functions accept same number of parameters (2 parameters) of same type (int), so according to general rules of function overloading – this case doesn’t seem to be overloaded functions. But let’s try to invoke these functions,
CTest objTest;
Int aVar = 5, bVar = 6;

objTest.add(aVar, bVar); // invokes pass-by-value version of add
Output: CTest::add(pass-by-value version)
objTest.add(&aVar, &bVar); // invokes pass-by-pointer version
Output: CTest::add(pass-by-pointer version)

As you can observe that,

> First function call invokes pass-by-value version of add method as the parameters are passed by value
> Second function call invokes pass-by-pointer version of add method as the parameters are passed by addresses.

Hence this is the case of function overloading.

Class Ctest also defines two versions of display() function as:

void display();
void display() const;


Let’s try to invoke these functions,

CTest objTest;
objTest.display(); // obviously invokes non-const version of display
Output: CTest::display(non-const version)

Now, modify above code a little-bit and see the results,

const CTest objTest;
objTest.display(); // surprise!!! Invokes const version of display
Output: CTest::display(const version)

The const keyword makes objTest as a constant object, so when there is call to display method it’s going to be resolved as
Display(const CTest &objTest)
This indicates that user is passing a constant object which doesn’t allow others to change it’s member variables, and who is the right candidate to make sure this? – it’s our constant member function.

This case also represents function overloading.

Summary
Function overloading depends on:
> number of parameters
> type of parameters
> how parameters are passed – pass-by-value or pass-by-pointer
> constness of function

I hope this explanation gives you some idea about some tricky ways of function overloading. Any suggestions, feedbacks are always welcome.

Sunday, June 21, 2009

MEMORY LAYOUT FOR VIRTUAL FUNCTIONS

This article is for beginners who wanted to gain in-depth knowledge about how virtual function works?

I will not be explaining definition & usage of virtual function, which one can get from MSDN or other C++ books.

Now let’s start understanding how a simple class is been laid out in Memory:

class Base

{
private:
    int iBVar;
public:

    void bMehtod1()
    {
        cout<<”Base::bMethod1()”;
    }
    void bMehtod2()
    {
        cout<<”Base::bMethod2()”;
    }
};
The memory layout for Base is:

As shown in above figure, the object derived from Base is been laid out in memory according to above figure.

Now let’s modify above Base class, add two virtual functions into it:

class Base

{
private:
    int iBVar;
public:
    void bMehtod1()
    {
        cout<<”Base::bMethod1()”;
    }
    void bMehtod2()
    {
        cout<<”Base::bMethod2()”;
    }

    virtual void bMethod3()
    {
        cout<<”Base::virtual::bMethod3()”;
    }
    virtual void bMethod4()
    {
        cout<<”Base::virtual::bMethod4()”;
    }

};



As shown in above figure, a Virtual Table is been added in-between class & Code Segment that contains entries for pointer to virtual functions. Let’s look into newly added items

vptr (Virtual Pointer):
> it’s the pointer which contain address of Virtual Table.
> vptr is associated with object, each object is having a different vptr pointing to same VTable.
> vptr is been added to object’s memory space only if atleast one virtual function is declared in a class.
> vptr is always been the first private member automatically added in a class by compiler.
> address of vptr is equal to base address of object. So if the base address of object get’s corrupted, invoking virtual function with corrupted object results into application crash.

Virtual Table (VTable):
> it’s a memory space reserved by compiler to place entries of the functions which are declared as virtual. The entries of virtual functions in VTable is according to their declaration in class. Here bMethod3() is added at offset zero whereas bMethod4() is added at offset 1.
> virtual table is associated with a class, so there will always been one VTable irrespective of any number of objects created for that class and each object share the same VTable.
For example,
Base obj1, obj2, obj3;
The memory layout for obj1, obj2 & obj3 is:




Let’s declare one more class publicly derived from Base to look at the virtual function from inheritance point-of-view:


class Derived: public Base
{
public:
    void bMethod3()
    {
        cout<<”Derived::bMethod3()”;
    }
};


When a class derived from it’s parent class (contain virtual function), at first instance the compiler copies entries of Base::VTable into Derived::VTable,

VTable for Base Class
==================
Base::bMethod3()
Base::bMethod4()

VTable for Derived Class
====================
Base::bMethod3()
Base::bMethod4()

So, even if Derived class doesn’t override any virtual method still it contain VTable.

Now, the compiler look into overridden methods in Derived class and replace old entries with overridden method entries. In our case, as bMethod3() is overridden in Derived class it’s entry get replaced in VTable of Derived class.
Updated VTable of Derived Class
===========================
Derived::bMethod3()
Base::bMethod4()

Let’s write a code to invoke these methods,

Base *pBase;
Base bObj;
Derived dObj;

bObj.bMethod3() // invokes Base::bMethod3()

pBase = &bObj;
pBase->bMethod3(); // invokes Base::bMethod3()

pBase = &dObj;
pBase->bMethod3(); // invokes Derived::bMethod3()

Let’s look at the pseudocode generated by Compiler for some of the above statements,

bObj.bMethod3();
Assembly Code: Call bMethod3()
Description: Resolved at compile time and doesn’t depend on any run-time values.


pBase->bMethod3()
Assembly Code: Call (Get first 4 bytes of address stored in pBase (i.e. vptr)->Get content of vptr (i.e. address of VTable)->Get address of function[offset])
Description: Resolved at compile time with dependency on run-time value of address stored in pBase, the exact content of pBase is decided at run-time only (like pBase = &bObj & pBase = &dObj). So, which version of method is been invoked totally depends on the address stored inside pBase. Hence using pBase one can call different methods, that is nothing but our own OOPS concept Polymorphism – one item taking different forms.


Hope that you get good understanding about virtual functions. A suggestions, feedbacks are always welcome.