【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)要求学生达到熟练掌握C++语言的基本知识和技能; (2)基本掌握面向对象程序设计的基本思和方法; (3)能够利用所学的基本知识和技能,解决简单的面向对象程序设计问题。 2、基本要求: (1)要求利用面向对象的方法以及C++的编程思想来完成系统的设计; (2)要求在设计的过程中,建立清晰的类层次; (3)在系统中至少要定义四个类,每个类中要有各自的属性和方法; (4)在系统的设计中,至少要用到面向对象的一种机制。 3、创新要求: 在基本要求达到后,可进行创新设计,如根据查找结果进行修改的功能及设计出比较友好的界面等。 4、写出设计说明书 二、设计方法和基本原理: 1、问题描述(功能要求): 某小型公司,主要有四类人员:经理、兼职技术人员、销售经理和兼职推销员。现在,需要存储这些人员的姓名、编号、级别、当月薪水,计算月薪总额并显示全部信息。 要求: 1)其中,人员编号在生成人员信息时同时生成,每输入一个人员信息编号顺序加1。 2)程序对所有人员有提升级别的功能 3)月薪的计算方法是:经理拿固定月薪,兼职技术人员按工作小时数领取月薪,兼职推销员的报酬按该推销员当月销售额提成 ,销售经理既拿固定月薪也领取销售提成。 4)能按姓名或者编号显示、查找、增加、删除和保存各类人员
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值