虚函数实现总结

转载一篇非常好的讲解c++ 虚函数的文章:http://www.cnblogs.com/chenyuming507950417/archive/2012/04/15/2449020.html

你也可以结合这篇文章一起看http://blog.csdn.net/chenlei0630/article/details/44096535,能够使你在虚函数实现上有个不错的认识!


我会对这篇文章的结论做一些总结,方便阅读。

总结:

虚函数实现中两个名词:虚指针(Virtual pointe),虚函数表(Virtual table)。

虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。

  1. 空的成员函数不占任何存储
  2. 一个Virtual pointe 占4个字节(32-bit machine)
  3. 多个虚函数保存的地址保存在虚函数表中,只需要一个Virtual pointe指向该虚函数表
  4. VPTR(Virtual pointe)存储在class的最开始的那部分空间
  5. 多继承需要多个虚函数指针和虚函数表。每个父类都有自己的虚表,子类的虚函数放在第一个基类的Virtual table 内,虚函数按照其声明顺序放于表中,父类的虚函数在子类的虚函数前面
  6. 没有成员的空类的存储空间sizeof 为1
  7. 派生类中对基类函数进行覆盖时,覆盖的函数被放在原来父类在续表中的位置,其他函数位置依旧



以下为转载内容

this article is about how vptr and virtual table works,and it comes fromhttp://www.dreamincode.net/forums/topic/45816-detail-about-how-vptr-and-virtual-table-works/

 

Assumption: machine is 32-bit .
Here I am going to explain How Virtual table, Virtual pointer for Virtual functions are internally working.

First we have understand memory layout.

 

 

Example 1: How the class's memory layout

复制代码
class Test 
{
  public:
    int data1;
    int data2;
    int fun1();
};

int main() 
{
  Test obj;
  cout << "obj's Size = " << sizeof(obj) << endl;
  cout << "obj 's Address = " << &obj << endl;
  return 0;
}
复制代码

Output:

Sobj's Size = 8
obj 's Address = 0012FF7C

Note: Any Plane member function does not take any memory.

 

 

Example 2: Memory Layout of Derived class

复制代码
class Test 
{
public:
  int a;
  int b;
};

class dTest : public Test
{
public:
  int c;
};

int main() 
{
  Test obj1;
  cout << "obj1's Size = " << sizeof(obj1) << endl;
  cout << "obj1's Address = " << &obj1 << endl;
  dTest obj2;
  cout << "obj2's Size = "<< sizeof(obj2) << endl;
  cout << "obj2's Address = "<< &obj2 << endl;
  return 0;
}
复制代码

OUTPUT:
obj1's Size = 8
obj1's Address = 0012FF78
obj2's Size = 12
obj2's Address = 0012FF6C

 

Example 3: Memory layout If we have one virtual function.

复制代码
class Test 
{
public:
  int data;
  virtual void fun1() 
  { 
    cout << "Test::fun1" << endl; 
  }
};

int main() 
{
  Test obj;
  cout << "obj's Size = " << sizeof(obj) << endl;
  cout << "obj's Address = " << &obj << endl;
  return 0;
}
复制代码

OUTPUT:

obj's Size = 8
obj's Address = 0012FF7C

Note: Adding one virtual function in a class takes 4 Byte extra.

 

Example 4: More than one Virtual function

复制代码
class Test 
{
public:
  int data;
  virtual void fun1() { cout << "Test::fun1" << endl; }
  virtual void fun2() { cout << "Test::fun2" << endl; }
  virtual void fun3() { cout << "Test::fun3" << endl; }
  virtual void fun4() { cout << "Test::fun4" << endl; }
};

int main()
 {
  Test obj;
  cout << "obj's Size = " << sizeof(obj) << endl;
  cout << "obj's Address = " << &obj << endl;
  return 0;
 }
复制代码

OUTPUT:

obj's Size = 8
obj's Address = 0012FF7C

Note: Adding more virtual functions in a class, no extra size taking i.e. Only one machine size taking(i.e. 4 byte)

 

Example 5:

复制代码
class Test
 {
public:
  int a;
  int b;
  Test(int temp1 = 0, int temp2 = 0)
  {
     a=temp1;
     b=temp2; 
  }
  int getA()  
  {
     return a;
  }
  int getB()  
  {
     return b;
  }
  virtual ~Test();
};

int main() 
{
  Test obj(5, 10);

// Changing a and b
  int* pInt = (int*)&obj;
  *(pInt+0) = 100;   
  *(pInt+1) = 200;   

  cout << "a = " << obj.getA() << endl;
  cout << "b = " << obj.getB() << endl;
  return 0;
}
复制代码

OUTPUT: 
a = 200
b = 10

If we Change the code as then

// Changing a and b
int* pInt = (int*)&obj;
*(pInt+1) = 100; // In place of 0
*(pInt+2) = 200; // In place of 1

OUTPUT:
a = 100
b = 200

Note: Who sits 1st place of Class : Answer is VPTR
VPTR - 1st placed in class and rest sits after it. 

 

Example 6:

复制代码
class Test 
{
  virtual void fun1() 
  {
     cout << "Test::fun1" << endl;
  }
};

int main() 
{
  Test obj;
  cout << "VPTR's Address " << (int*)(&obj+0) << endl;
  cout << "VPTR's Value " << (int*)*(int*)(&obj+0) << endl;
  return 0;
}
复制代码

OUTPUT:

VPTR's Address 0012FF7C
VPTR's Value 0046C060

NOTE: This VPTR's value is a address of Virtual table. Lets see in next Example.

 

Example 7:

复制代码
#include <iostream>
using namespace std;

class Test
 {
   virtual void fun1() 
   { 
    cout << "Test::fun1" << endl; 
   }
};
typedef void (*Fun)(void);

int main() 
{
  Test obj;
  cout << "VPTR's Address " << (int*)(&obj+0) << endl;
  cout << " VIRTUAL TABLE 's Address " << (int*)*(int*)(&obj+0) << endl; // Value of VPTR
  cout << "Value at first entry of VIRTUAL TABLE " << (int*)*(int*)*(int*)(&obj+0) << endl;
  
  Fun pFun = (Fun)*(int*)*(int*)(&obj+0);   // calling Virtual function
  pFun();
  return 0;
}
复制代码

OUTPUT:
VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Test: fun1

 

Example 8:

复制代码
class Test
{
  virtual void fun1() { cout << "Test::fun1" << endl; }
  virtual void func1() { cout << "Test::func1" << endl; }
};

int main()
 {
  Test obj;

  cout << "VPTR's Address " << (int*)(&obj+0) << endl;
  cout << "VIRTUAL TABLE 's Address"<< (int*)*(int*)(&obj+0) << endl;

  // Calling Virtual table functions
  cout << "Value at 1st entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+0) << endl;
  cout << "Value at 2nd entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+1) << endl;

  return 0;
}
复制代码

OUTPUT:

VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Value at 2nd entry of VIRTUAL TABLE 004012

 

Example :9

复制代码
class Test
{
  virtual void fun1() { cout << "Test::fun1" << endl; }
  virtual void func1() { cout << "Test::func1" << endl; }
};

typedef void(*Fun)(void);

int main() 
{
  Test obj;
  Fun pFun = NULL;
  
  // calling 1st virtual function
  pFun = (Fun)*((int*)*(int*)(&obj+0)+0);
  pFun();

  // calling 2nd virtual function
  pFun = (Fun)*((int*)*(int*)(&obj+0)+1);
  pFun();

  return 0;
}
复制代码

OUTPUT: 

Test::fun1
Test::func1

 

Example 10: multiple Inheritance

复制代码
class Base1 
{
public:
  virtual void fun();
};

class Base2 
{
public:
  virtual void fun();
};

class Base3 
{
public:
  virtual void fun();
};

class Derive : public Base1, public Base2, public Base3 
{
};

int main() 
{
  Derive obj;
  cout << "Derive's Size = " << sizeof(obj) << endl;
  return 0;
}
复制代码

OUTPUT:

Derive's Size = 12

 

Example 11: Calling Virtual Functions in case of Multiple Inheritance

复制代码
class Base1 
{
  virtual void fun1() { cout << "Base1::fun1()" << endl; }
  virtual void func1() { cout << "Base1::func1()" << endl; }
};

class Base2 {
  virtual void fun1() { cout << "Base2::fun1()" << endl; }
  virtual void func1() { cout << "Base2::func1()" << endl; }
};

class Base3 {
  virtual void fun1() { cout << "Base3::fun1()" << endl; }
  virtual void func1() { cout << "Base3::func1()" << endl; }
};

class Derive : public Base1, public Base2, public Base3 
{
public:
  virtual void Fn() 
  { 
  cout << "Derive::Fn" << endl; 
  }
  virtual void Fnc() 
  { 
  cout << "Derive::Fnc" << endl; 
  }
};

typedef void(*Fun)(void);

int main()
{
  Derive obj;
  Fun pFun = NULL;
  
  // calling 1st virtual function of Base1
  pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+0);
  pFun();

  // calling 2nd virtual function of Base1
  pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1);
  pFun();

  // calling 1st virtual function of Base2
  pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+0);
  pFun();

  // calling 2nd virtual function of Base2
  pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+1);
  pFun();

  // calling 1st virtual function of Base3
  pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+0);
  pFun();

  // calling 2nd virtual function of Base3
  pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+1);
  pFun();

  // calling 1st virtual function of Drive
  pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2);
  pFun();

  // calling 2nd virtual function of Drive
  pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+3);
  pFun();

  return 0;
}
复制代码

OUTPUT:

Base1::fun
Base1::func
Base2::fun
Base2::func
Base3::fun
Base3::func
Drive::Fn
Drive::Fnc


By
Asadullah Ansari 

 

others about vptr and virtual :

(1)http://blog.csdn.net/haoel/article/details/1948051

(2)http://topic.csdn.net/u/20120413/22/4691a553-ab7d-4a5b-b14b-757a2676c328.html?64575

(3)http://blog.csdn.net/hairetz/article/details/4137000

(4)http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值