C++三大特性之多态(二)---深度剖析各种虚继承虚函数以及虚表的内容存放

来源:互联网 发布:nginx 拦截指定域名 编辑:程序博客网 时间:2024/06/15 19:45

虚继承

(1).单继承

#include<iostream>using  namespace std ;class B{public:virtual void Funtest1(){cout << "B::Funtest1()" << endl;}virtual void Funtest2(){cout << "B::Funtest2()" << endl;}public:int _data1;};class D:virtual public B{public:D(){}virtual void Funtest1(){cout << "D::Funtest1()" << endl;}virtual void Funtest3(){cout << "D::Funtest3()" << endl;}int _data2;};void test0(){D d1;d1._data1 = 2;d1._data2 = 3;cout << "sizeof(D)=" << sizeof(D) << endl;cout << "继承过来的基类的虚函数的虚表:"<<endl;B &b1 = d1;typedef void (*PVF)();PVF*pvf = (PVF*)*(int*)&b1;while (*pvf){(*pvf)();  //通过这个循环打印出虚表中存放的函数。pvf++;}cout << endl;pvf = (PVF*)*(int*)&d1;//对象的前四个字节存放一个指针,这个指针指向一个虚表,虚表中存放的都是函数入口地址。//这一句就相当于一个函数指针类型的指针去指向一个函数指针类型的数组。cout << "派生类自己新增的虚函数构成的虚表:"<<endl;while (*pvf){(*pvf)();  //通过这个循环打印出虚表中存放的函数。pvf++;}cout <<endl;}int main(){test0();system("pause");return 0;}

说明:从基类继承过来的虚表也是先拷贝一份基类的虚表,如果派生类中有虚函数重写,则用派生类中的虚函数代替基类中的虚函数,派生类中新增的虚函数构成一张虚表,如果派生类中没有新增虚函数,则不会有这张虚表,因此就不会有前四个字节去存放虚表的地址。如果派生类中既没有构造函数也没有析构函数,则不会有0x00000000这四个字节。简单的演示下这两种情况:

1)将派生类中新增的FunTest3()函数屏蔽,也即是派生类中没有新增的虚函数,再来看下内存:

2)将派生类中的构造函数屏蔽,放开刚刚屏蔽的FunTest3()函数。也就是派生类中既没有构造函数也没有析构函数,在来看下内存:


(2)多继承

注释:此代码中派生类中没有构造函数也没有析构函数,派生类中有自己新增的虚函数。


#include<iostream>using  namespace std ;class C1{public:virtual void Funtest1(){cout << "C1::Funtest1()" << endl;}virtual void Funtest2(){cout << "C1::Funtest2()" <<endl;}public:int _data2;};class C2{public:virtual void Funtest3(){cout << "C2::Funtest1()" << endl;}virtual void Funtest4(){cout << "C2::Funtest3()" <<endl;}public:int _data3;};class D:virtual public C1,virtual public C2{public:virtual void Funtest4(){cout << "D::Funtest3()" << endl;}virtual void Funtest2(){cout << "D::Funtest2()" <<endl;}virtual void Funtest7()   //派生类的虚函数。{cout << "D::Funtest7()" <<endl;}virtual void Funtest8()  //派生类的虚函数。{cout << "D::Funtest8()" <<endl;}public:int _data4;};void test(){cout << "sizeof(D):" << sizeof(D) << endl;  //sizeof(D):28   D d1;cout << "&d1" << &d1 <<endl;  //看下派生类的地址。&d10051F98Cd1._data2 = 2;d1._data3 = 3;d1._data4 = 4;C1 &c1 = d1;cout << "&c1" << &c1 <<endl;  //看下基类C1去引用一个派生类,基类的地址。&c10051F998typedef void (*PVF)();PVF *pvf =  (PVF*)*(int*)&c1; //这就相当于一个二级指针指向一个指针数组。cout << "从C1继承过来的虚函数构成的虚表 :" << endl;while (*pvf){(*pvf)();pvf++;}cout  << endl << endl;C2 &c2 = d1;  //c2的地址就是d1偏移C1类型的地址。cout << "&c2" << &c2 <<endl;  //看下基类C2去引用一个派生类,基类的地址。&c20051F9A0pvf =  (PVF*)*(int*)&c2; //这就相当于一个二级指针指向一个指针数组。cout << "从C2继承过来的虚函数构成的虚表:" << endl;while (*pvf){(*pvf)();*pvf++;}cout  << endl;pvf =  (PVF*)*(int*)&d1; //这就相当于一个二级指针指向一个指针数组。cout << "派生类自己的虚函数构成的虚表:" << endl;while (*pvf){(*pvf)();*pvf++;}cout  << endl;}int main(){test();cout << "hello..." <<endl;system("pause");return 0;}


说明:先拷贝基类的虚表,如果派生类中有虚函数重写,用重写的虚函数代替原来的虚函数,其他的不变,同样的如果派生类中有构造函数和析构函数之一或两者都有,则会多有四个字节存放0x00000000,如果派生类中没有新增虚函数,则不会有第一张虚表,因此也不会有前四个字节存放第一张虚表的地址。

(3)菱形继承

注释:此代码中派生类中没有构造函数也没有析构函数,派生类中有自己新增的虚函数。

#include<iostream>using  namespace std ;class B{public:virtual void Funtest1(){cout << "B::Funtest1()" << endl;}public:int _data1;};class C1:virtual public B{public:virtual void Funtest1(){cout << "C1::Funtest1()" << endl;}virtual void Funtest2(){cout << "C1::Funtest2()" <<endl;}public:int _data2;};class C2:virtual public B{public:virtual void Funtest1(){cout << "C2::Funtest1()" << endl;}virtual void Funtest3(){cout << "C2::Funtest3()" <<endl;}public:int _data3;};class D:public C2,public C1{public:virtual void Funtest1(){cout << "D::Funtest1()" << endl;}virtual void Funtest3(){cout << "D::Funtest3()" << endl;}virtual void Funtest4(){cout << "D::Funtest4()" <<endl;}public:int _data4;};void test(){cout << "sizeof(D):" << sizeof(D) << endl;  //sizeof(D):28   c1 12+c2 12+d 4   = 28D d1;d1._data1 = 1;d1._data2 = 2;d1._data3 = 3;d1._data4 = 4;C1 &c1 = d1;typedef void (*PVF)();PVF *pvf =  (PVF*)*(int*)&c1; //这就相当于一个二级指针指向一个指针数组。cout << "从C1继承过来的虚函数构成的虚表:" << endl;while (*pvf){(*pvf)();pvf++;}cout  << endl << endl;C2 &c2 = d1;pvf =  (PVF*)*(int*)&c2; //这就相当于一个二级指针指向一个指针数组。cout << "从C2继承过来的虚函数构成的虚表:" << endl;while (*pvf){(*pvf)();*pvf++;}cout  << endl;B &b1 = d1;pvf =  (PVF*)*(int*)&b1; //这就相当于一个二级指针指向一个指针数组。cout << "从基类B继承的虚函数构成的虚表:" << endl;while (*pvf){(*pvf)();*pvf++;}cout  << endl;}int main(){test();cout << "hello..." <<endl;system("pause");return 0;}





0 0
原创粉丝点击