菱形继承和虚函数

来源:互联网 发布:md5加盐加密java代码 编辑:程序博客网 时间:2024/06/05 19:47

此篇博客主要介绍菱形虚拟继承和虚函数的混合情况下的模型分析。

一.首先介绍一下虚函数的实质内容

1.没有虚继承的虚函数

class A{public:int a;virtual void fun1(){cout << "A::fun1 " << endl;}};class B :public A{public:int b;virtual void fun1()//函数重写  {cout << "B::fun1 " << endl;}virtual void fun2(){cout << "B::fun2" << endl;}};int main(){B b;//创建一个B的对象  A a;        b.b = 20;a.a = 10;b.a = 30;system("pause");return 0;}

首先我们来看对象a的虚函数机制


接下里我们对B对象虚表里面的 函数进行验证,对象自己验证

typedef void(*fun)();//这里定义fun为函数指针类型fun *p = (fun *)*(int*)(&b);(*p)();//打印B::fun1         p++;//指向B::fun2        (*p)();//打印B::fun2


2.有虚继承的虚函数

首先看这个类的大小:

class A{public:int a;virtual void fun1(){cout << "A::fun1 "<< endl;}};class B :virtual public A{public:int b;virtual void fun1()//函数重写{cout << "B::fun1 " << endl;}virtual void fun2(){cout << "B::fun2" << endl;}};int main(){    B b;    A a;    b.b=20;    a.a=10;    sizeof(B);    system("pause");    return 0;}

刚才无虚继承的类大小是12怎么加了个vurtual虚继承以后就变成了20呢?一下多了八个字节,接下来我们详细分析。


接下来打印验证:

typedef void(*fun)();//这里定义fun为函数指针类型fun *p = (fun *)*(int*)(&b);(*p)();p += 4;;(*p)();

3.菱形继承➕虚函数
首先给出基本代码:

class A{public:int _a;virtual void fun1(){cout << "A::fun1" << endl;}virtual void fun2(){cout << "A::fun2" << endl;}};class B1 : virtual public A{public:int _b1;virtual void fun1(){cout << "B1::fun1" << endl;}virtual void fun3(){cout << "B1::fun3" << endl;}};class B2 :virtual public A{public:int _b2;virtual void fun1(){cout << "B2::fun1" << endl;}virtual void fun4(){cout << "B2::fun4" << endl;}};class C :public B1,public B2{public:int _c;virtual void fun1(){cout << "C::fun1" << endl;}virtual void fun3(){cout << "C::fun3" << endl;}virtual void fun4(){cout << "C::fun4" << endl;}virtual void fun5(){cout << "C::fun5" << endl;}};int main(){cout <<"A:"<< sizeof(A) << endl;cout << "B1:"<<sizeof(B1) << endl;cout << "B2:"<<sizeof(B2) << endl;cout << "C:"<<sizeof(C) << endl;A a;B1 b1;B2 b2;C c;a._a = 10;b1._a = 10;b1._b1 = 20;b2._b2 = 30;b2._a = 10;c._c = 40;c._a = 10;c._b1 = 20;c._b2 = 30;system("pause");return 0;}

先来看看每个对象的大小然后我在逐个对象分析其模型



注意这里的B是B1,图上写的是B


接下来打印验证

typedef void(*fun)();//这里定义fun为函数指针类型fun *p = (fun *)*(int*)(&c);(*p)();//C::fun3(*(p + 1))();//C::fun5(*(p + 3))();//C::fun4(*(p + 5))();//C::fun1(*(p + 6))();//A::fun2


总结:1.无虚继承时在虚函数中,派生类中的虚函数非基类重写,则将其放置在继承来的虚函数表后面,不重新开辟虚函数表,并且将派生类中重写的虚函数替换基类中的虚函数

             2.有虚继承虚函数时,派生类中的虚函数如果不是基类的重写的话,新开辟一个虚函数表将未重写虚函数放进去,将继承来的虚函数表放在其后面,并且将重写的替换

             3.菱形继承+虚函数时,最重要的一点就是在,最低层的派生类中(上述例子就是C),只有一份基类(A)的虚表,并且在其模型(C模型)的最下面。并且将其没有重写的虚函数放在第一个继承模型(B1)的虚函数表下面,而且将其重写的也要替换为自己的。

阅读全文
0 0