Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C++ (http://www.go4expert.com/articles/cpp-tutorials/)
-   -   Virtual Table and _vptr in Replicated and Shared Multiple Inheritance (http://www.go4expert.com/articles/virtual-table-vptr-replicated-shared-t16789/)

Mridula 3Apr2009 19:07

Virtual Table and _vptr in Replicated and Shared Multiple Inheritance
 

Introduction



This article talks about Virtual Table and _vptr in Replicated Multiple Inheritance and in Virtual Base Class (or Shared Multiple Inheritance).

Here it is explained using an example:

In this example, we have Base1, Base2, Base3 and Derive classes, where Base2 and Base3 classes are derived from Base1 class and Derive class is derived from Base2 and Base3 classes.

Background



Replicated Multiple Inheritance:

Here, Base2 and Base3 classes are derived Normally from Base1 class, there is a duplicate data and methods of Base1 class to Derive class (from Base2 and Base3 classes) and when we try to access that common data or functions through Derive object, there will be a ambiguity in accessing it.

As I have already explained in my last artcile (it is listed in reference part here), in Mupltile Inheritance, Derive classes (which has been derived from more than one base class) will have it's Base classe's VPTR with it. And it's own virtual functions will be listed as part of it's first Base classes virtual table.

For Replicated MI example, if we take teh object memory map for Derive class's object, functions and data of it's base classes will be listed as below:

vptr and data of class Base2 - contains virtual methods of Base1, Base2(self), then Derive class's ones, i.e.:
---------
Base1 class Virtual Methods
Base2 class virtual Methods
Base2 class data (if any)
Derive class virtual Methods

then
vptr and data of class Base3 - contains virtual methods of Base1 and Base3 (self):
---------
Base1 class Virtual Methods
Base3 class Virtual Methods
Base3 class Data (if any)

Derive data
------------
Derive class Data

Also Size of the Derive object would be:

_vptr of Base2 class + data of Base2 class
+ _vptr of Base3 class + data of Base3 class
+ data of Derive class

The same is explained here in this example code and o/p too is given:

Here for this example, we can not have Data for Base1 class and if we try to have, will get a compilation error (amgibuous) for Base1's member data.

If you, observe the memory map for object Derive d, the virtual functions of foremost base class i.e. Base1 class is duplicated in both the vtables of classes Base2 and Base3.

The code



Replicated Multiple Inheritance example


Code: Cpp

#include<iostream.h>

class Base1
{
  public:
    virtual void func1(void){cout<<"Base1::func1\n";};
};

class Base2 : public Base1
{
  public:
    int a;
    virtual void func2(void){cout<<"Base2::func2\n";};
};

class Base3 : public Base1{
  public:
    virtual void func3(void){cout<<"Base3::func3\n";};
};

class Derive: public Base2, public Base3
{
  public:
    int b;

    virtual void func4(void){cout<<"Derive::func4\n";};
};

typedef void (*fun) (void);

int main()
{
  Derive d;
  int* vptr;

  fun funp=NULL;

  cout<<"Size of Derive object d is = "<<sizeof(d)<<endl<<endl;

  cout<< "Memory map of Derive object d :\n";
  cout<<"------------------------------------\n\n";

  // calling virtual function func1 of Base1
  funp = (fun)*((int*)*(int*)((int*)&d+0)+0);
  funp();

  // calling virtual function func2 of Base2
  funp = (fun)*((int*)*(int*)((int*)&d+0)+1);
  funp();

  // calling virtual function func4 of Derive
  funp = (fun)*((int*)*(int*)((int*)&d+0)+2);
  funp();
 
  // accessing and changing the variable of Base2
  int* pInt = (int*)&d+1;
  *(pInt+0) = 30;
  cout<<"Base2 class data: a =" << d.a <<endl;

  // calling virtual function func1 of Base1
  funp = (fun)*((int*)*(int*)((int*)&d+2)+0);
  funp();
 
  // calling virtual function func3 of Base3
  funp = (fun)*((int*)*(int*)((int*)&d+2)+1);
  funp();

  // accessing and changing the variable of Derive
  pInt = (int*)&d+3;
  *(pInt+0) = 100;
  cout<<"Derive class data: b =" << d.b <<endl;

  return(0);
}

output
-----
Size of Derive object d is = 16

Memory map of Derive object d :
------------------------------------

Base1::func1
Base2::func2
Derive::func4
Base2 class data: a =30
Base1::func1
Base3::func3
Derive class data: b =100


So for the above code (size of Derive object "d" is):

4 bytes (_vptr of Base2) +
4 bytes (data i.e. int a of Base2 class) +
4 bytes (_vptr of Base3 class) +
4 bytes (data i.e. int b of Derive class)

that equates to 16


Here you can see the pictorial view of memory map for Derive class object


http://www.go4expert.com/images/arti...e/rep-vtbl.jpg

Shared Multiple Inheritance or Virtual Base class

As a solution for not to replicate the members and data of foremost base class, we go for Virtual Base classes.

So, for our above example, we need to make class Base1 as Virtual base class for class Base2 and class Base3, then derive class Derive from Base2 and Base3.

I have noticed 2 different memory-map for Derive object for Virual Base or Shared Multiple Inheritance as below:

1. When foremost base class has only virtual functions and no data to share.
2. When foremost base class has some data and/or virtual functions


For the first case, if we check the memory map for Derive class object, it is as below i.e:

vptr and data of Base2 class - contains foremost class i.e. Base1, Base2 and Derive class virtual methods:
----------
Base1 class Virtual Functions
Base2 class Virtual Functions
Derive class Virtual Functions
Base2 data

vptr and data of Base3 class - contains only Base3 virtual methods and contains
pointers to Base1 class (common class) virtual methods
------------
Pointers to virtual functions of Base1 class
Base3 class Virtual Methods
Base3 data

Data of Derive class
----------
Derive class data


Also the Size of the Derive object would be:

_vptr of Base2 class + data of Base2 class
+ _vptr of Base3 class + data of Base3 class
+ data of Derive class

The same is explained here in this example code and o/p too is given:

The code



Shared Mutiple Inheritance without data eample


Code: Cpp

#include<iostream.h>

class Base1
{
  public:
    virtual void func1(void){cout<<"Base1::func1\n";};
};

class Base2 : virtual public Base1
{
  public:
    int a;
    virtual void func2(void){cout<<"Base2::func2\n";};
};

class Base3 : virtual public Base1{
  public:
    virtual void func3(void){cout<<"Base3::func3\n";};
};

class Derive: public Base2, public Base3
{
  public:
    int b;
    virtual void func4(void){cout<<"Derive::func4\n";};
};

typedef void (*fun) (void);

int main()
{
  Derive d;

  fun funp=NULL;

  cout<<"Size of Derive object d is = "<<sizeof(d)<<endl<<endl;

  cout<< "Memory map of Derive object d :\n";
  cout<<"------------------------------------\n\n";

  // calling virtual function func1 of Base1
  funp = (fun)*((int*)*(int*)((int*)&d+0)+0);
  funp();

  // calling virtual function func2 of Base2
  funp = (fun)*((int*)*(int*)((int*)&d+0)+1);
  funp();

  // calling virtual function func4 of Derive
  funp = (fun)*((int*)*(int*)((int*)&d+0)+2);
  funp();
 
  // accessing and changing the variable of Base2
  int* pInt = (int*)&d+1;
  *(pInt+0) = 30;
  cout<<"Base2 class Data: a =" << d.a <<endl;

  // calling virtual function func3 of Base3
  funp = (fun)*((int*)*(int*)((int*)&d+2)+1);
  funp();
 
  cout<<"Base3 class Data if any (there is no data for Base3 class here in example)" <<endl;
 
  // accessing and changing the variable of Derive
  pInt = (int*)&d+3;
  *(pInt+0) = 100;
  cout<<"Derive class Data: b =" << d.b <<endl<<endl;

  return(0);
}

output
-----
Size of Derive object d is = 16

Memory map of Derive object d :
------------------------------------

Base1::func1
Base2::func2
Derive::func4
Base2 class Data: a =30
Base3::func3
Base3 class Data if any (there is no data for Base3 class here in example)
Derive class Data: b =100


So for the above code (size of Derive object "d" is):

4 bytes (_vptr of Base2) +
4 bytes (data i.e. int a of Base2 class) +
4 bytes (_vptr of Base3 class) +
4 bytes (data i.e. int b of Derive class)

that equates to 16

Here you can see the pictorial view of memory map for Derive class object


http://www.go4expert.com/images/arti.../shr-vtbl1.JPG

For the second case i.e. if foremost class contains some data along with/without virtual functions, then object memory of Derive class object will be as shown below:

vptr and data of Base2 class - contains only Base2 (self) and Derive class virtual methods:
----------
Base2 class Virtual Functions
Derive class Virtual Functions
Base2 data

vptr and data of Base3 class - contains only Base3 virtual methods
------------
Base3 class Virtual Methods
Base3 data

Data of Derive object and vptr of foremost Base class and it's data
----------
Derive class data
virtual functions of foremost class i.e. Base1 class
Data of foremost class i.e. Base1 class

Also Size of the Derive object would be:

_vptr of Base2 class + data of Base2 class +
_vptr of Base3 class + data of Base3 class +
data of Derive class +
_vptr of Base1 class + data of Base1 class


The same is explained here in this example code and o/p too is given:

The code



Shared Multiple Inheritance with Data

Code: Cpp

#include<iostream.h>

class Base1
{
  public:
    virtual void func1(void){cout<<"Base1::func1\n";};
    int a;
};

class Base2 : virtual public Base1
{
  public:
    int b;
    virtual void func2(void){cout<<"Base2::func2\n";};
};

class Base3 : virtual public Base1{
  public:
    virtual void func3(void){cout<<"Base3::func3\n";};
};

class Derive: public Base2, public Base3
{
  public:
    int c;
    virtual void func4(void){cout<<"Derive::func4\n";};
};

typedef void (*fun) (void);

int main()
{
  Derive d;

  fun funp=NULL;

  cout<<"Size of Derive object d is = "<<sizeof(d)<<endl<<endl;

  cout<< "Memory map of Derive object d :\n";
  cout<<"------------------------------------\n\n";

  // calling virtual function func1 of Base2
  funp = (fun)*((int*)*(int*)((int*)&d+0)+0);
  funp();

  // calling virtual function func4 of Derive
  funp = (fun)*((int*)*(int*)((int*)&d+0)+1);
  funp();

  // accessing and changing the variable of Base2
  int* pInt = (int*)&d+1;
  *(pInt+0) = 30;
  cout<<"Base2 class Data: b =" << d.b <<endl;

  // calling virtual function func3 of Base3
  funp = (fun)*((int*)*(int*)((int*)&d+2)+0);
  funp();
 
  cout<<"Base3 class Data if any (there is no data for Base3 class here in example)" <<endl;

  // accessing and changing the variable of Derive
  pInt = (int*)&d+3;
  *(pInt+0) = 60;
  cout<<"Derive class Data: c =" << d.c <<endl;

  // calling virtual function func1 of Base1
  funp = (fun)*((int*)*(int*)((int*)&d+4)+0);
  funp();
 
  // accessing and changing the variable of Base1
  pInt = (int*)&d+5;
  *(pInt+0) = 120;
  cout<<"Base1 class Data: a =" << d.a <<endl<<endl;

  return(0);
}

output
-----
solutionWithData.cc

Size of Derive object d is = 24

Memory map of Derive object d :
------------------------------------

Base2::func2
Derive::func4
Base2 class Data: b =30
Base3::func3
Base3 class Data if any (there is no data for Base3 class here in example)
Derive class Data: c =60
Base1::func1
Base1 class Data: a =120


So for the above code (size of Derive object "d" is):

4 bytes (_vptr of Base2 class) +
4 bytes (data i.e. int b of Base2 class) +
4 bytes (_vptr of Base3 class) +
4 bytes (data i.e. int c of Derive class)
4 bytes (_vptr of Base1 class) +
4 bytes (data i.e. int a of Base1 class)

that eqautes to 24

If you notice here, the size of the Derive object differs in both the cases as explained above.


Here you can see the pictorial view of memory map for Derive class object

http://www.go4expert.com/images/arti...shr-vtbl12.JPG


References



How Virtual Table and _vptr works

How Virtual Table and _vptr works

Virtual Table and _vptr in Multiple Inheritance

Virtual Table and _vptr in Multiple Inheritance

asadullah.ansari 6Apr2009 12:07

Re: Virtual Table and _vptr in Replicated and Shared Multiple Inheritance
 
Extremely nice article...Keep posting such nice atricles...

Mridula 6Apr2009 13:50

Re: Virtual Table and _vptr in Replicated and Shared Multiple Inheritance
 
If you like it so much, please vote for me later.

many thanks
Mridula.

shabbir 3May2009 11:58

Re: Virtual Table and _vptr in Replicated and Shared Multiple Inheritance
 
Nominate this article of the month for April 2009

shabbir 18May2009 19:45

Re: Virtual Table and _vptr in Replicated and Shared Multiple Inheritance
 
Start Voting for article of the month - April 2009


All times are GMT +5.5. The time now is 09:39.