多继承三角和钻石问题(虚继承)

上一篇文章我们简单介绍了一下多继承的语法,但是我们遇到了一个问题,那就是如果多个父类具有相同名称的成员变量或成员方法,子类在调用的时候就会出现二义性问题,子类不知道选择哪一个父类的变量或方法,我们称之为三角问题。如下所示:

2015-05-24_192636

所以在编译的时候程序就无法通过了。其实解决这个问题有很多办法,先说一个最简单的办法就是使用域运算符,直接使用某个父类的成员函数或变量。如下所示:

#include <iostream>

using namespace std;

class Bed
{
public:
	void sleep()
	{
		cout << "Bed Sleep ~~" << endl;
	}
protected:
	int data;
};

class Sofa
{
public:
	void sit()
	{
		cout << "Sofa sit ~~" << endl;
	}
protected:
	int data;
};

// 继承多个父类
class Derive : public Bed, public Sofa
{
public:
	Derive()
		:Bed(), Sofa() {}

	void display()
	{
		// 使用作用域运算符,直接指定调用某个父类的成员
		cout << Bed::data << endl;
		cout << Sofa::data << endl;
	}
};

int main(int argc, char* argv[])
{
	Derive SofaBed;
	SofaBed.sleep();
	SofaBed.sit();
	SofaBed.display();
	return 0;
}

这是一种解决办法,当然,本文介绍的绝不止这些。在设计类的过程中,如果多个父类出现了同名的公有成员变量或方法,并且方法所执行的认为是一模一样的情况下,这证明我们设计的类是有问题的,应该保证实现同一功能的方法只有一个。那在上面的案例中我们需要抽象出一个基类,这个基类将Sofa和Bed两个类的公有同名变量或成员存放到基类中,然后让 Sofa 和 Bed 使用虚继承的方式,继承这个基类,这时,子类再多继承 Sofa 和 Bed 类的时候,就不会出现二义性问题了。其中 虚继承 起到了重要的作用,他让基类派生的两个类只保留了一份共有公共成员,这种情况,我们称之为钻石问题。

2015-05-24_194407

2015-05-24_192917

#include <iostream>

using namespace std;

class M
{
public:
	int data;
};

// 虚继承 M 类
class Bed : virtual public M
{
public:
	void sleep()
	{
		cout << "Bed Sleep ~~" << endl;
	}
};

// 虚继承 M 类
class Sofa : virtual public M
{
public:
	void sit()
	{
		cout << "Sofa sit ~~" << endl;
	}
};

// 继承多个父类
class Derive : public Bed, public Sofa
{
public:
	Derive()
		:Bed(), Sofa() {}

	void display()
	{
		// 无需再担心二义性问题
		cout << data << endl;
	}
};

int main(int argc, char* argv[])
{
	Derive SofaBed;
	SofaBed.sleep();
	SofaBed.sit();
	SofaBed.display();
	return 0;
}

说说你的想法