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继承与派生之高级篇--派生类与赋值运算符及多重继承的主要内容,如果未能解决你的问题,请参考以下文章