C++之多重继承

大多数应用程序使用单个基类的公用继承,但是在某些情况下,单继承是不够的,必须使用多继承。C++允许为一个派生类指定多个基类,这样的继承结构被称做多重继承.

举个例子,交通工具类可以派生出汽车和船连个子类,但拥有汽车和船共同特性水陆两用汽车就必须继承来自汽车类与船类的共同属性。如下图示:

代码实现:

//多重继承
 #include <iostream>
 using namespace std;
 class Vehicle
 {
 public:
 	Vehicle(int weight = 0)
 	{
 		Vehicle::weight = weight;
 	}
 	void SetWeight(int weight)
 	{
 		cout << "重新设置重量" << endl;
 		Vehicle::weight = weight;
 	}
 	virtual void ShowMe() = 0;//纯虚函数
 protected:
 	int weight;
 private:
 };

 class car:public Vehicle//汽车
 {
 public:
 	car(int weight = 0, int aird = 0) :Vehicle(weight)
 	{
 		car::aird = aird;
 	}
 	void ShowMe()
 	{
 		cout << "我是汽车!" << endl;
 	}
 protected:
 	int aird;
 private:
 };

 class boat:public Vehicle//船
 {
 public:
 	boat(int weight = 0, float tonnage = 0) :Vehicle(weight)
 	{
 		boat::tonnage = tonnage;
 	}
 	void ShowMe()
 	{
 		cout << "我是船!" << endl;
 	}
 protected:
 	float tonnage;
 private:
 };

 class AmphibianCar :public car, public boat//水陆两用汽车,多重继承的体现
 {
 public:
 	AmphibianCar(int weight, int aird, float tonnage)
 		:Vehicle(weight), car(weight, aird), boat(weight, tonnage)
		//多重继承要注意调用基类构造函数
 	{

 	}
 	void ShowMe()
 	{
 		cout << "我是水陆两用汽车!" << endl;
 	}
 };

 int main()
 {
 	AmphibianCar a(4, 200, 1.35f);//错误
 	a.SetWeight(3);//错误
 	system("pause");
 }

上面的代码从表面看,看不出有明显的语发错误,但是它是不能够通过编译的。错误如下:

这有是为什么呢? 这是由于多重继承带来的继承的模糊性带来的问题。

先看如下的图示:

在图中深红色标记出来的地方正是主要问题所在,水陆两用汽车类继承了来自Car类与Boat类的属性与方法,Car类与Boat类同为AmphibianCar类的基类,在内存分配上AmphibianCar获得了来自两个类的SetWeight()成员函数,当我们调用a.SetWeight(3)的时候计算机不知道如何选择分别属于两个基类的被重复拥有了的类成员函数SetWeight()。

以上面的代码为例,我们要想让AmphibianCar类既获得一个Vehicle的拷贝,而且又同时共享用Car类与Boat类的数据成员与成员函数就必须通过C++所提供的虚拟继承技术来实现。

在Car类和Boat类继承Vehicle类时前面加上virtual关键字就可以实现虚拟继承,使用虚拟继承后,当系统碰到多重继承的时候就会自动先加入一个Vehicle的拷贝,当再次请求一个Vehicle的拷贝的时候就会被忽略,保证继承类成员函数的唯一性。

修改后的代码:

//加virtual后的正确代码
 #include <iostream>
 using namespace std;

class Vehicle
{
public:
	Vehicle(int weight = 0)
	{
		Vehicle::weight = weight;
		cout << "载入Vehicle类构造函数" << endl;
	}
	void SetWeight(int weight)
	{
		cout << "重新设置重量" << endl;
		Vehicle::weight = weight;
	}
	virtual void ShowMe() = 0;
protected:
	int weight;
};
class Car :virtual public Vehicle//汽车,这里是虚拟继承
{
public:
	Car(int weight = 0, int aird = 0) :Vehicle(weight)
	{
		Car::aird = aird;
		cout << "载入Car类构造函数" << endl;
	}
	void ShowMe()
	{
		cout << "我是汽车!" << endl;
	}
protected:
	int aird;
};

class Boat :virtual public Vehicle//船,这里是虚拟继承
{
public:
	Boat(int weight = 0, float tonnage = 0) :Vehicle(weight)
	{
		Boat::tonnage = tonnage;
		cout << "载入Boat类构造函数" << endl;
	}
	void ShowMe()
	{
		cout << "我是船!" << endl;
	}
protected:
	float tonnage;
};

class AmphibianCar :public Car, public Boat//水陆两用汽车,多重继承的体现
{
public:
	AmphibianCar(int weight, int aird, float tonnage)
		:Vehicle(weight), Car(weight, aird), Boat(weight, tonnage)
		//多重继承要注意调用基类构造函数
	{
		cout << "载入AmphibianCar类构造函数" << endl;
	}
	void ShowMe()
	{
		cout << "我是水陆两用汽车!" << endl;
	}
	void ShowMembers()
	{
		cout << "重量:" << weight << "顿," << "空气排量:" << aird << "CC," << "排水量:" << tonnage << "顿" << endl;
	}
};
int main()
{
	AmphibianCar a(4, 200, 1.35f);
	a.ShowMe();
	a.ShowMembers();
	a.SetWeight(3);
	a.ShowMembers();
	system("pause");
}

输出:

虽然说虚拟继承与虚函数有一定相似的地方,但务必要记住,他们之间是绝对没有任何联系的!

************************************************************************************************************************

************************************************************************************************************************

总结多继承的一些要点和注意事项:

  • 多重继承的情况下,遇到二义性的可能将会更大,编译器不会试图根据派生类转换区别基类间的转换,转换成每个基类都一样好,有如下代码:
class ZooAnimal
{

};

class Bear : public ZooAnimal
{

};

class Endangered
{

};

class Panda : public Bear, public Endangered
{

};

如果有print函数的两个重载版本:

void print(const Bear&);

void print(const Endangered&);

这个调用将会出错,编译器将指出改掉用有二义性。

  • 假定在类的多个基类中定义了相同的成员,将会导致二义性,如果定义了同名的成员函数,即使是函数参数不同,也会导致二义性,代码如下:
class ZooAnimal
{

};

class Bear : public ZooAnimal
{
public:
void print(int x){cout<<"print"<<endl;}

};

class Endangered
{
public:
void print(){cout<<"print"<<endl;};
};

class Panda : public Bear, public Endangered
{
};

如果在ZooAnimal中定义了print 而Bear中没有定义,同样会出现二义性。避免二义性的最好方法就是指定函数的作用域,比如:

Bear::print(x);

The End!

时间: 2024-08-15 09:25:52

C++之多重继承的相关文章

016: class and objects &gt; 多重继承与多态的例子

房屋代理模型: 1. Property class Property(object): def __init__(self, square_feet='', num_bedrooms='', num_baths='', **kwargs): super().__init__(**kwargs) self.square_feet = square_feet self.num_bedrooms = num_bedrooms self.num_baths = num_baths def display

C++多重继承中构造函数和析构函数调用顺序举例

//多重继承 #include <iostream> using namespace std; class A { public:     A()     {         cout<<"A基类构造A::A()"<<endl;     }     ~A()     {         cout<<"A基类析构A::~A()"<<endl;     } }; class B:public A { publi

C++多重继承关系举例

//多重继承 #include <iostream> using namespace std; class A { public:     int a;     A(int a=0):a(a)     {         cout<<"A基类A::A()"<<endl;     }     ~A()     {         cout<<"A基类A::~A()"<<endl;     }     void

C++多重继承中的虚继承和虚函数举例

上一篇虚继承举例:http://10638473.blog.51cto.com/10628473/1964414 本文将A类中的show()函数前加上virtual关键字. //多重继承 #include <iostream> using namespace std; class A { public:     int a;     A(int a=0):a(a)     {         cout<<"A基类A::A()"<<endl;     

Java提高篇——Java实现多重继承

阅读目录 一. 接口二.内部类 多重继承指的是一个类可以同时从多于一个的父类那里继承行为和特征,然而我们知道Java为了保证数据安全,它只允许单继承.有些时候我们会认为如果系统中需要使用多重继承往往都是糟糕的设计,这个时候我们往往需要思考的不是怎么使用多重继承,而是您的设计是否存在问题.但有时候我们确实是需要实现多重继承,而且现实生活中也真正地存在这样的情况,比如遗传:我们即继承了父亲的行为和特征也继承了母亲的行为和特征.可幸的是Java是非常和善和理解我们的,它提供了两种方式让我们曲折来实现多

JS---原型继承和多重继承

概念: 1.原型继承是创建新类型对象----子类型,子类型基于父类型,子类型拥有父类型所有的属性和方法(从父类型继承得到),然后修改其中的部分内容或者添加新的内容.继承最好在子类型模型可以被视为父类型对象的时候使用. 2.从多个父类型中派生出一个对象类型称为多重继承. 一.原型继承 使用new关键字和构造函数的prototype属性都是定义类型的特定方式,这些是我们到目前为止一直使用的,对于简单的对象,这种方式还是很好的,但是当程序过度使用继承时,这种创建对象的方法很快就显得笨拙了.所以增加一些

多重继承,虚继承,MI继承中虚继承中构造函数的调用情况

先来测试一些普通的多重继承.其实这个是显而易见的. 测试代码: [cpp] view plain copy print? //测试多重继承中派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace std; class base { public: base() { cout<<"base created!"<<endl; } ~base()

第53课 被遗弃的多重继承(上)

1. 单一继承 (1)实验代码 #include <iostream> #include <string> using namespace std; void visitVtbl(int **vtbl) { cout << vtbl << endl; cout << "\t[-1]: " << (long)vtbl[-1] << endl; typedef void (*FuncPtr)(); int

php通过接口实现多重继承

php是单重继承的.一个类只有一个父类. 但是可以通过接口实现多重继承. 定义了一个接口,接口中有方法,假如接口给类去implements了,那么那个类需要有接口的方法.就像下面的代码 <?php interface d{ function b(); } class a implements d{ function b(){} } ?> 但是,如果a的类里面没有function b,就会报错 Fatal error: Class a contains 1 abstract method and