【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,如果自动将所有类都处理为虚继承,程序运行将有很大的时间与空间上的开销。

本章总结


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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值