C++多态实现原理

理论知识:

当类中声明虚函数时,编译器会在类中生成一个虚函数表。

虚函数表是一个存储类成员函数指针的数据结构。

虚函数表是由编译器自动生成与维护的。

virtual成员函数会被编译器放入虚函数表中。

当存在虚函数时,每个对象中都有一个指向虚函数表的指针(C++编译器给父类对象、子类对象提前布局vptr指针;当进行howToPrint(Parent *base)函数是,C++编译器不需要区分子类对象或者父类对象,只需要再base指针中,找vptr指针即可。)。

VPTR一般作为类对象的第一个成员。

多态的实现原理

说明1:

通过虚函数表指针VPTR调用重写函数是在程序运行时进行的,因此需要通过寻址操作才能确定真正应该调用的函数。而普通成员函数是在编译时就确定了调用的函数。在效率上,虚函数的效率要低很多。

说明2:

出于效率考虑,没有必要将所有成员函数都声明为虚函数。

demo

[cpp] view plaincopyprint?

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. //多态成立的三个条件   
  5. //要有继承  虚函数重写  父类指针指向子类对象   
  6.   
  7. class Parent  
  8. {  
  9. public:  
  10.     Parent(int a=0)  
  11.     {  
  12.         this->a = a;  
  13.     }  
  14.   
  15.     virtual void print()  //1 动手脚  写virtal关键字 会特殊处理 //虚函数表  
  16.     {  
  17.         cout<<"父类"<<endl;  
  18.     }  
  19.     virtual void print2()  //1 动手脚  写virtal关键字 会特殊处理 //虚函数表  
  20.     {  
  21.         cout<<"父类"<<endl;  
  22.     }  
  23. private:  
  24.     int a;  
  25. };  
  26.   
  27. class Child : public Parent  
  28. {  
  29. public:  
  30.     Child(int a = 0, int b=0):Parent(a)  
  31.     {  
  32.         this->b = b;  
  33.     }  
  34.   
  35.     virtual void print()  
  36.     {  
  37.         cout<<"子类"<<endl;  
  38.     }  
  39. private:  
  40.     int b;  
  41. };  
  42.   
  43. void HowToPlay(Parent *base)  
  44. {  
  45.     base->print(); //有多态发生  //2 动手脚    
  46.     //效果:传来子类时,执行子类的print函数,传来父类时执行父类的print函数   
  47.     //C++编译器根本不需要区分是子类对象,还是父类对象  
  48.     //父类对象和子类对象分步有vptr指针 , ==>虚函数表===>函数的入口地址  
  49.     //迟绑定 (运行时的时候,c++编译器才去判断)  
  50. }  
  51.   
  52. int main()  
  53. {  
  54.   
  55.     Parent  p1; //3 动手脚 提前布局    
  56.                 //用类定义对象的时候,C++编译器会在对象中添加一个vptr指针   
  57.     Child   c1; //子类里面也有一个vptr指针  
  58.   
  59.     HowToPlay(&p1);  
  60.     HowToPlay(&c1);  
  61.   
  62.     return 0;  
  63. }  

说明3 :C++编译器,执行HowToPrint函数,不需要区分是子类对象还是父类对象

下面来证明vptr指针的存在。

demo

[cpp] view plaincopyprint?

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4.   
  5. class Parent1  
  6. {  
  7. public:  
  8.     Parent1(int a=0)  
  9.     {  
  10.         this->a = a;  
  11.     }  
  12.   
  13.     void print()   
  14.     {  
  15.         cout<<"父类"<<endl;  
  16.     }  
  17. private:  
  18.     int a;  
  19. };  
  20.   
  21. class Parent2  
  22. {  
  23. public:  
  24.     Parent2(int a=0)  
  25.     {  
  26.         this->a = a;  
  27.     }  
  28.   
  29.     virtual void print()    
  30.     {  
  31.         cout<<"虚析构函数的父类"<<endl;  
  32.     }  
  33. private:  
  34.     int a;  
  35. };  
  36.   
  37. int main()  
  38. {  
  39.     printf("sizeof(Parent):%d sizeof(Parent2):%d \n", sizeof(Parent1), sizeof(Parent2));  
  40.     // 结果是普通类大小为4,而把函数变成虚构函数之后大小为8,所以证明了这里vptr指针的存在性  
  41.   
  42.     return 0;  
  43. }  

猜你喜欢

转载自blog.csdn.net/dijuzhu2350/article/details/81100775