c++的探索路12继承与派生之高级篇--派生类与赋值运算符及多重继承(代码片段)

Guerrouj Guerrouj     2022-12-11     499

关键词:

本部分为新版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++的探索路11继承与派生之拓展篇--多形式派生以及派生类指针转换(代码片段)

本篇文章将在基础篇的基础上进行相应的拓展,依次介绍:多层次派生、公有派生的赋值兼容规则、派生类与基类的指针互换以及私有派生和保护派生。书中对应章节如下多层次派生基本概念多层次派生就像一系列的亲... 查看详情

关于c++基类与派生类

...动态联编那C++定义基类和派生类的初衷是:为了让派生类继承基类啊。为什么动态联编又把基类和子类联系起来了呢?我认为它违背了一个宗旨:让派生类继承基类。谁能打破我对基类与派生类的认知???通过继承机制,可以... 查看详情

c++的探索路15多态与虚函数之高级篇(代码片段)

本部分是多态与虚函数主要内容的完结篇,这一部分将介绍虚析构函数以及纯虚函数和抽象类,结束本章后下一部分将为习题课的练习。虚析构函数为了担心说起来太抽象,先扔一个程序#include<iostream>usingnamespaces... 查看详情

面向对象之继承与派生(代码片段)

一、继承  1、含义:继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题。  2、特点:继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,而... 查看详情

面向对象之继承与派生

阅读目录一初识继承二继承与抽象(先抽象再继承)三继承与重用性四派生五组合与重用性六接口与归一化设计七抽象类八 继承实现的原理(可恶的菱形问题)九子类中调用父类的方法一初识继承什么是继承继承指的是类与... 查看详情

part7继承与派生7.3基类与派生类类型转换

...为基类的指针。 通过基类对象名、指针只能使用从基类继承的成员。 //7-3类型转换规则举例#include<iostream>usingnamespacestd;classBase1{public:voiddisp 查看详情

面向对象之继承与派生(代码片段)

继承:单继承/多继承python2与python3在继承上的区别:  新式类:但凡继承object类的子类,以及该子类的子子类,...都称之为新式类  经典类:没有继承object类的子类,以及该子类的子子类,...都称之为经典类只有在python2中才区分新式类... 查看详情

派生类与继承

1、下面的程序可以输出ASCII字符与所对应的数字的对照表。修改下列程序,使其可以输出字母a到z(或任意两个字符间)与所对应的数字的对照表。classtable{  public:     table(intp)     {&nbs... 查看详情

12.抽象与密封

...2、抽象类特性:  (1)抽象类不能实例化,必须通过继承由派生类来实现其抽象方法。如果派生类没有实现所有的抽象方法,则该派生类也必须声明为抽象类。  (2)抽象类的非抽象子类(即派生类)必须通过重载实现其... 查看详情

c++认知继承(代码片段)

对于继承,这是C++中相当重要的语法,学习此语法可以更好的认知C++这个恢弘的世界。介绍继承类继承举例类继承的认知继承关系和访问限定符private访问与protected访问的区别分析访问限定与继承方法的排列组... 查看详情

类的继承与派生(代码片段)

第5章类的继承与派生1类的继承与类的派生继承人们追求代码复用(这是提高软件开发效率的重要手段),将继承和派生用于程序设计方法中,从而有了面向对象程序设计的重要特点。C++对代码复用有很强的支持,继承就是支持代... 查看详情

回顾c++:访问权限控制之公有保护私有继承用法详解与总结(代码片段)

...符:主要用于控制派生类实例对基类的成员访问权限公有继承->保护继承->私有继承,派生类实例对基类成员的访问权限束缚依次加强。除公有继承外,保护继承相当于重置基类公有成员为保护成员,私有继承相当于重置基类... 查看详情

c++:-4

...节学习了C的数组,指针和字符串,c++:-3。本节学习C的继承与派生:##继承###继承和派生的关系继承与派生是同一过程从不同的角度看保持已有类的特性而构造新类的过程称为继承在已有类的基础上新增自己的特性而产生新类的... 查看详情

继承与派生(代码片段)

继承继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可以成为基类或超类,新建的类... 查看详情

c++笔记之多态(代码片段)

...虚函数的重写虚函数重写的两个例外1.协变(基类与派生类虚函数返回值类型不同)2.析构函数的重写(基类与派生类析构函数的名字不同)重载、覆盖(重写)、隐藏(重定义)重载与覆盖令人迷... 查看详情

深度探索c++关键字之virtual(代码片段)

    virtual在C++中有两个重要的用途:一是解决由多继承中父类有相同基类引起的子类中成员的二义性问题,二是实现多态。一、解决二义性1、引起二义性的原因    二义性是在多继承中出现的,如果派生类... 查看详情

继承与派生(代码片段)

继承1.什么是继承?  在程序中继承是一种新建子类的方式新创建的类称之为之类派生类被继承的类称之为父类基类超类2.为何要用继承?  减少类与类之间代码冗余的问题3.如何继承?  先抽象再继承 python中继承的特... 查看详情

继承与派生(代码片段)

初识继承什么是继承?继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可以成... 查看详情