菱形继承和虚函数

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

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

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)的虚函数表下面,而且将其重写的也要替换为自己的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值