C++的探索路12继承与派生之高级篇--派生类与赋值运算符及多重继承

Posted Guerrouj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++的探索路12继承与派生之高级篇--派生类与赋值运算符及多重继承相关的知识,希望对你有一定的参考价值。

本部分为新版C++程序设计教程之继承与派生部分的最后一小部分,内容涉及派生类与赋值运算符以及多重继承。

整体框架如下

派生类和赋值运算符

派生类的默认复制构造函数会调用基类的复制构造函数;同理,如果基类重载了赋值运算符“=”而派生类没有,那么在派生类对象之间赋值活用派生类对象对基类对象进行赋值时,基类部分的赋值操作是调用被基类重载的赋值运算符来完成的。

one more coding

class CBase 
public:
	CBase()
		cout << "你猜 called" << endl;
	
	CBase(CBase&c) 
		cout << "CBase copy constructor called" << endl;
	
	CBase&operator=(CBase&b) 
		cout << "CBase operator = called" << endl;
		return *this;
	
;
class CDerived :public CBase 

;
int main() 
	CDerived d1, d2;
	CDerived d3(d1);
	d2 = d1;
	return 0;


多重继承

基础概念

之前学习了一个概念叫多层次派生,这一部分引入一个新概念:多重继承。这两个词貌似有点相近,但也有区别:多层次派生,注重的是层次,指的是上下等级的意思;而多重派生注重的是重,多次使用的意思。

多重继承简称为多继承,实现方式是继承多个直接基类,其代码形式为:

class 派生类名:派生方式说明符 基类1,派生方式说明符 基类2,....

However,有一利必有一弊,多重继承的弊端还比较大;导致java直接放弃了使用多重继承这一编程思想;其弊端在于二义性,如果继承的两个基类均由同一个层级更高的基类派生而来,那么多重继承时,将在类内出现重复成员。

例子

对于多重继承的bug,通过一个例子来学习一下:

程序中需要对一个销售经理类的对象进行设置基础信息、销售量的输入以及信息打印的操作。

而销售经理显然具备销售人员(CEmployee)以及经理(CManager)的共同属性,而销售人员及经理又具备雇员类的基本信息,所以按照流程依次继承。

雇员类

雇员类包含的成员变量有:姓名、年龄以及性别。

而成员函数则包括:

构造函数CEmployee(),打印基本信息函数PrintBasicInfo()以及设置基础信息SetBasicInfo()三个函数

销售类

具备成员变量,销售额:salesVolume对绩效进行评估

经理类

额外包含下辖员工数量:totalSubordinates进行员工管辖

销售经理类

继承销售类以及经理类,并能通过setInfo()对类进行赋值,通过PrintInfo()对内部信息进行打印。

#include<string>
class CEmployee 
	string name;
	int age;
	char gender;
public:
	CEmployee() 
		cout << "CEmployee constructor" << endl;
	
	void PrintBasicInfo() 
		cout << "Name: " << name << endl;
		cout << "Age: " << age << endl;
		cout << "Gender: " << gender << endl;
	
	void SetBasicInfo(const string &name_, int age_, char gender_) 
		name = name_;
		age = age_;
		gender = gender_;
	
;
class CSalesman :public CEmployee 
protected:
	int salesVolume;
;
class CManager :public CEmployee 
protected:
	int totalSubordinates;
;
class CSalesManager :public CSalesman, public CManager 
public:
	void setInfo(int sv, int sn) 
		salesVolume = sv;
		totalSubordinates = sn;
	
	void PrintInfo() 
		CSalesman::PrintBasicInfo();
		cout << "Sales Volume: " << salesVolume << endl;
		cout << "Total Subordinates: " << totalSubordinates << endl;
	
;
int main() 
	CSalesManager sm;
	sm.CSalesman::SetBasicInfo("Tom", 24, 'M');
	sm.setInfo(100000, 20);
	sm.PrintInfo();
	return 0;

结构如下


上面程序中接连出现了两次域作用符

依次在CSalesManager类的PrintInfo中,另外一次在主函数的SetBasicInfo中。

这是为了避免出现二义性:

在PrintInfo中去掉域作用符则不知道调用的是CSalesman的PrintBasicInfo还是CManager的PrintBasicInfo。

同理主函数中也是一样的问题。

所以,解决二义性的第一种方法为:域作用符

相关Bug

如果主程序的域设置为CManager则会出现内存问题:因为乱认主人

咨询链接

虚继承去除二义性

除了使用域作用符声明这是我的地盘外,C++提供了虚继承的概念去除二义性:就是在每个派生的类的继承方式说明符前面加上virtual关键字

比如上面的程序改写为:

#include<string>
class CEmployee 
	string name;
	int age;
	char gender;
public:
	CEmployee() 
		cout << "CEmployee constructor" << endl;
	
	void PrintBasicInfo() 
		cout << "Name: " << name << endl;
		cout << "Age: " << age << endl;
		cout << "Gender: " << gender << endl;
	
	void SetBasicInfo(const string &name_, int age_, char gender_) 
		name = name_;
		age = age_;
		gender = gender_;
	
;
class CSalesman :virtual public CEmployee 
protected:
	int salesVolume;
;
class CManager :virtual public CEmployee 
protected:
	int totalSubordinates;
;
class CSalesManager :public CSalesman, public CManager 
public:
	void setInfo(int sv, int sn) 
		salesVolume = sv;
		totalSubordinates = sn;
	
	void PrintInfo() 
		PrintBasicInfo();
		cout << "Sales Volume: " << salesVolume << endl;
		cout << "Total Subordinates: " << totalSubordinates << endl;
	
;
int main() 
	CSalesManager sm;
	sm.SetBasicInfo("Tom", 24, 'M');
	sm.setInfo(100000, 20);
	sm.PrintInfo();
	return 0;

Something difference:

构造函数相较于上面只调用了一次,说明CSalesManager类的对象中只有一个CEmployee对象。

其他bug:

1,假如A派生出类B,C,D;而E继承于B,C,D三个类,如果BCD三个类前面都加了virtual关键字,那么好说:避免了二义性,但如果B,C前面加了virtual而D没有,那么依然会出现二义性的现象!!

2,如果自动将所有类都处理为虚继承,程序运行将有很大的时间与空间上的开销。

本章总结


接下来一小节将进行继承与派生这部分的习题课内容。

以上是关于C++的探索路12继承与派生之高级篇--派生类与赋值运算符及多重继承的主要内容,如果未能解决你的问题,请参考以下文章

C++的探索路13继承与派生之练习篇(需重新学习)

C++的探索路14多态与虚函数之基础篇

总结C++基类与派生类的赋值兼容规则

详解C++中基类与派生类的转换以及虚基类

关于C++基类与派生类

C++的探索路15多态与虚函数之高级篇