一直以来,c++的虚函数以及虚继承令人讨厌。下面通过程序彻底了解c++的虚函数以及虚继承。
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;};//构造函数不能为virtual函数 }; classB2:public B1 { public: B2(){cout<<"B2 constructor"<<endl;};//构造函数不能为virtual函数 void f2(){ cout << "B2::f2" << endl; } }; classB3:public B1 { public: B3(){cout<<"B3 constructor"<<endl;};//构造函数不能为virtual函数 void f3(){ cout << "B3::f3" << endl; } }; classD :public B2,public B3 { public: D(){cout<<"D constructor"<<endl;};//构造函数不能为virtual函数 void v3(){ cout << "D::v3" << endl; } }; //======================================= int main (int argc,constchar * argv[]) { cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
基类中不含虚函数以及不使用虚拟继承时,基类与派生类的size都为1.运行上面的程序,可以看到下面的结果:
继续考虑虚继承对类size的影响。
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; }; classB2:publicvirtual B1 { public: B2(){cout<<"B2 constructor"<<endl;}; void f2(){ cout << "B2::f2" << endl; } }; classB3:public virtual B1 { public: B3(){cout<<"B3 constructor"<<endl;}; voidf3(){ cout << "B3::f3"<< endl; } }; classD :public B2,public B3 { public: D(){cout<<"D constructor"<<endl;}; void v3(){cout <<"D::v3" <<endl; } }; //======================================= intmain (int argc,constchar * argv[]) { cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
运行程序,可以看到它的地址表格如下:
继承类虚拟继承基类时,继承类的size变成4,这是为什么???
而考虑菱形结构的虚继承的另外一种方式:
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; }; classB2:public B1 { public: B2(){cout<<"B2 constructor"<<endl;}; void f2(){ cout << "B2::f2" << endl; } }; classB3:public B1 { public: B3(){cout<<"B3 constructor"<<endl;}; voidf3(){ cout << "B3::f3"<< endl; } }; classD :public virtual B2,publicvirtual B3 { public: D(){cout<<"D constructor"<<endl;}; void v3(){cout <<"D::v3" <<endl; } }; //======================================= intmain (int argc,constchar * argv[]) { cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
继承类虚拟继承基类时,继承类的size变成4,这是为什么???
菱形虚拟继承的常见方式:
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; }; classB2:public virtual B1 { public: B2(){cout<<"B2 constructor"<<endl;}; void f2(){ cout << "B2::f2" << endl; } }; classB3:public virtual B1 { public: B3(){cout<<"B3 constructor"<<endl;}; voidf3(){ cout << "B3::f3"<< endl; } }; classD :public virtual B2,publicvirtual B3 { public: D(){cout<<"D constructor"<<endl;}; void v3(){cout <<"D::v3" <<endl; } }; //======================================= intmain (int argc,constchar * argv[]) { cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
继承类虚拟继承基类时,继承类的size变成4,这是为什么???
接着考虑,基类中有虚函数,无虚继承的情况:
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; virtual voidv1(){ cout << "B1::v1"<< endl; } }; classB2:public B1 { public: B2(){cout<<"B2 constructor"<<endl;}; virtualvoid v2(){ cout <<"B2::v2"<< endl; } //如果基类中有虚函数,那么该类中有无虚函数对本类无影响 void f2(){ cout << "B2::f2" << endl; } }; classB3:public B1 { public: //int z; B3(){cout<<"B3 constructor"<<endl;}; virtualvoid v3(){ cout <<"B3::v3"<< endl; } void f3(){ cout << "B3::f3" << endl; } }; classD :public B2,public B3 { public: D(){cout<<"D constructor"<<endl;}; voidv3(){ cout << "D::v3"<< endl; } virtual voidvD(){ cout << "D::vD"<< endl; } }; intmain (int argc,constchar * argv[]) { // insert code here... cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
其结果发生了较大改变:
前面都是对称的情况,下面考虑一些非对称的情形。例如:基类B1中无虚函数,而B2、B3有虚函数,无虚继承
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; //virtual voidv1(){ cout << "B1::v1"<< endl; } }; classB2:public B1 { public: B2(){cout<<"B2 constructor"<<endl;}; virtualvoid v2(){ cout <<"B2::v2"<< endl; } //如果基类中有虚函数,那么该类中有无虚函数对本类无影响 void f2(){ cout << "B2::f2" << endl; } }; classB3:public B1 { public: //int z; B3(){cout<<"B3 constructor"<<endl;}; virtualvoid v3(){ cout <<"B3::v3"<< endl; } void f3(){ cout << "B3::f3" << endl; } }; classD :public B2,public B3 { public: D(){cout<<"D constructor"<<endl;}; voidv3(){ cout << "D::v3"<< endl; } virtual void vD(){ cout << "D::vD"<< endl; } //只要类B2或者B3含有虚函数,该类中有无虚函数无所谓,因为是public继承的原因 }; intmain (int argc,constchar * argv[]) { // insert code here... cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
基类中无虚函数,继承类中有虚函数
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; //virtual voidv1(){ cout << "B1::v1"<< endl; } }; classB2:public B1 { public: B2(){cout<<"B2 constructor"<<endl;}; //virtualvoid v2(){ cout <<"B2::v2"<< endl; } void f2(){ cout << "B2::f2" << endl; } }; classB3:public B1 { public: //int z; B3(){cout<<"B3 constructor"<<endl;}; //virtualvoid v3(){ cout <<"B3::v3"<< endl; } void f3(){ cout << "B3::f3" << endl; } }; classD :public B2,public B3 { public: D(){cout<<"D constructor"<<endl;}; voidv3(){ cout << "D::v3"<< endl; } virtual voidvD(){ cout << "D::vD"<< endl; } }; intmain (int argc,constchar * argv[]) { // insert code here... cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
B1无虚函数,B2、B3虚继承B1,D继承B2、B3为public
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; //virtual void v1(){ cout <<"B1::v1" << endl; } //void f1(){cout << "B1::f1"<< endl; } }; classB2:public virtual B1 { public: B2(){cout<<"B2 constructor"<<endl;}; virtual voidv2(){ cout << "B2::v2"<< endl; } void f2(){ cout << "B2::f2" << endl; } }; classB3:publicvirtualB1 { public: B3(){cout<<"B3 constructor"<<endl;}; virtual voidv3(){ cout << "B3::v3"<< endl; } void f3(){ cout << "B3::f3" << endl; } }; classD :public B2,public B3 { public: D(){cout<<"D constructor"<<endl;}; void v3(){ cout << "D::v3" << endl; } virtual void vD(){ cout << "D::vD"<< endl;//有无虚函数都是16bytes,因为是公共继承 } }; //======================================= intmain (int argc,constchar * argv[]) { // insert code here... cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
B1有虚函数,B2、B3虚继承B1,并且B2、B3没有虚函数,D继承B2、B3为public,D中没有虚函数
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; virtual voidv1(){cout << "B1::v1"<< endl; } }; classB2:public virtual B1 { public: B2(){cout<<"B2 constructor"<<endl;}; void f2(){ cout << "B2::f2" << endl; } }; classB3:publicvirtualB1 { public: B3(){cout<<"B3 constructor"<<endl;}; void f3(){ cout << "B3::f3" << endl; } }; classD :public B2,public B3 { public: D(){cout<<"D constructor"<<endl;}; void v3(){ cout << "D::v3" << endl; } }; //======================================= intmain (int argc,constchar * argv[]) { // insert code here... cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
B1含有虚函数,B2和B3虚继承B1,B2和B3也含有虚函数,D公共继承B2和B3,此时D有无虚函数无所谓
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; virtual voidv1(){ cout << "B1::v1"<< endl; } //void f1(){cout << "B1::f1"<< endl; } }; classB2:public virtual B1 { public: //int y; B2(){cout<<"B2 constructor"<<endl;}; virtualvoid v2(){ cout <<"B2::v2"<< endl; } void f2(){ cout << "B2::f2" << endl; } }; classB3:publicvirtualB1 { public: B3(){cout<<"B3 constructor"<<endl;}; virtualvoid v3(){ cout <<"B3::v3"<< endl; } void f3(){ cout << "B3::f3" << endl; } }; classD :public B2,public B3 { public: D(){cout<<"D constructor"<<endl;}; void v3(){cout <<"D::v3" <<endl; } virtual voidvD(){ cout << "D::vD"<< endl; } }; //======================================= intmain (int argc,constchar * argv[]) { cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
B1含有虚函数,B2和B3公共继承B1(此时B2和B3有无虚函数无所谓),D虚拟继承B2、B3,那么D有无虚函数对D有影响
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; virtual void v1(){ cout << "B1::v1"<< endl; } }; classB2:public B1 { public: B2(){cout<<"B2 constructor"<<endl;}; virtualvoid v2(){ cout <<"B2::v2"<< endl; } }; classB3:public B1 { public: B3(){cout<<"B3 constructor"<<endl;}; virtualvoid v3(){ cout <<"B3::v3"<< endl; } void f3(){ cout << "B3::f3" << endl; } }; classD :publicvirtualB2,publicvirtualB3 { public: D(){cout<<"D constructor"<<endl;}; void v3(){cout <<"D::v3" <<endl; } virtual voidvD(){ cout << "D::vD"<< endl; } }; intmain (int argc,constchar * argv[]) { cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
如果D中无虚函数,具体结果如下图
D中无虚函数,各个类的size如左下图
如果D中有虚函数,各个类的size如右上图,具体的类结构见下图:
B2和B3虚拟继承B1(此时B1有无虚函数有影响),D虚拟继承B2、B3,那么B2、B3、D有无虚函数对B2、B3、都有D有影响
#include <iostream> using namespace std; //查看虚函数表 classB{}; classB1 { public: B1(){cout<<"B1 constructor"<<endl;}; virtual voidv1(){ cout << "B1::v1"<< endl; } }; classB2:publicvirtualB1 { public: B2(){cout<<"B2 constructor"<<endl;}; virtualvoid v2(){ cout <<"B2::v2"<< endl; } void f2(){ cout << "B2::f2" << endl; } }; classB3:public virtual B1 { public: B3(){cout<<"B3 constructor"<<endl;}; virtualvoid v3(){ cout <<"B3::v3"<< endl; } void f3(){ cout << "B3::f3" << endl; } }; classD :publicvirtualB2,publicvirtualB3 { public: D(){cout<<"D constructor"<<endl;}; void v3(){cout <<"D::v3" <<endl; } virtual voidvD(){ cout << "D::vD"<< endl; } }; //======================================= intmain (int argc,constchar * argv[]) { cout<<sizeof(B)<<endl; cout<<sizeof(B1)<<endl; cout<<sizeof(B2)<<endl; cout<<sizeof(B3)<<endl; cout<<sizeof(D)<<endl; D* d=new D; B1* b1=new B1; B2* b2=new B2; B3* b3=new B3; d->v3(); return 0; }
若D中没有虚函数,那么D的size为24,即为B2和B3的size之和即不会共享相同的B1中的对象,其他类的size不变。
上面的两个结果为类D中有无成员方法V3()的结果,有V3时D的size为28,没有V3时D的size为24.而在B1、B2、B3中有无非虚成员方法对各个类无影响。
上面的两个结果为类D有虚函数,并且D中有无成员方法V3()的结果,有V3时D的size为28,没有V3时D的size为24.而在B1、B2、B3中有无非虚成员方法对各个类无影响。