C++之继承详解

一.继承基础知识

继承定义:

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保
原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象
程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继
承是类设计层次的复用

 

例如:

class Person
{
public:
	//
private:
	int _age;
	string cellphone;
	string name;
};
class Student :public Person
{
public:
	//
private:
	int _student_id;
};
class Teacher :public Person
{
public:
	//
private:
	int _teacher_id;
};

你仔细观察上面代码,会发现再学生和老师类上我们后面都跟了:public Person说明这两个类是继承Person的内容

现在我们再来学习下格式:

定义格式:

关于派生类和基类大家看下都能理解,现在我们重点来讲解下什么是继承方式

继承方式简单理解就是子类对于父类中的成员可以进行的操作,如下:

类成员/继承方式public继承protected继承private继承
基类的public成员派生类的public成员派生类的protected
成员
派生类的private
成员
基类的protected
成员
派生类的protected
成员
派生类的protected
成员
派生类的private
成员
基类的private成
在派生类中不可见在派生类中不可见在派生类中不可 见

总结:
1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私
有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面
都不能去访问它

2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在
派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的
3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他
成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected
> private。

4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过
最好显示的写出继承方式。
5. 在实际运用中一般使用都是public继承,几乎

很少使用protetced/private继承,也不提倡
使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里
面使用,实际中扩展维护性不强

 

二.基类和派生类对象赋值转换

派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片
或者切割
。寓意把派生类中父类那部分切来赋值过去。
基类对象不能赋值给派生类对象。
基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类
的指针是指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用RTTI(RunTime Type Information)的dynamic_cast 来进行识别后进行安全转换

 

如下:

class Person
{
public:
private:
	int age;
	string name;
};
class Student :public Person
{
public:
private:
	string _id;
};
class Teacher :public Person
{
public:
private:
	string _id;
};
int main()
{
	Student s;
	//子类可以切片给父类对象
	//派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用
	//派生类对象 可以赋值给 基类的对象
	Person p1 = s;
	//派生类对象 可以赋值给 基类的指针
	Person* p2 = &s;
	//派生类对象 可以赋值给 基类的引用
	Person& p3 = s;
	//但注意;基类不能赋值给派生类
	Person p4;
	//Teacher t1 = p4;
	return 0;
}

但基类一定不能传给派生类吗???

我们发现此时是可以赋值给子类了,这是特殊情况的处理,而且转换时可能会出现越界的情况

知识扩展:

我们知道在不同类型赋值时会存在类型转换,那么你知道下面这行代码出错的原因吗???

看到报错原因,你以为是int不能传给double,还是要强制类型转换

实际上这是因为引用赋值时,会产生一个临时变量,该零时变量具备常性,所以我们必须用const修饰,防止权限扩大

这样就可以通过了

总结:如果要通过引用来复制拷贝,我们一定要观察是否会出现零时变量,从而确定是否需要用const修饰

三.继承中的作用域

1. 在继承体系中基类和派生类都有独立的作用域
2. 子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,
也叫重定义
。(在子类成员函数中,可以使用 基类::基类成员 显示访问
3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏
4. 注意在实际中在继承体系里面最好不要定义同名的成员

 

如果你仔细观察过上一个代码,你会发现在Student和Teacher中都出现了_id这个成员变量,这就是隐藏

下面在看这道题:

class A
{
public:
	void func()
	{
		//
	}
private:
	int _a;
};
class B :public A
{
public:
	void func(int a=10)
	{
		//
	}
private:
	int _a;
};

请问B中的func函数和A中的func函数是什么关系???

a.   无关系                         b.  重定义(隐藏)                           c.重载

答案是:b

c重载是指在相同作用域中两个同名函数由于参数的不同所构成的,而且只有返回类型不同是不构成重载的

而且这两个类属于不同作用域,看定义:
成员函数的隐藏,只需要函数名相同就构成隐藏

那么我们如何访问父类成员变量呢???

如下:

四.派生类的默认成员函数(重点)

class Person
{
public:
	//构造函数;
	Person(const string& s)
		:_name(s)
	{}
	//拷贝构造
	Person(const Person& p)
		:_name(p._name)
	{}
	//复值重载
	Person& operator=(const Person& p)
	{
		if (&p != this)
		{
			this->_name = p._name;
			return *this;
		}
		else
		{
			exit(-1);
		}
	}
	//析构函数
	~Person()
	{
		//析构
	}
protected:
	string _name;
};
class Student :public Person
{
public:
	//构造函数;
	//派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认
	//的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用
	Student(const Student& s)
		:_age(s._age),Person(s)
	{}
	Student(const int& age,const string& name)
		:_age(age),Person(name)
	{}
	//注意的是:构造函数实际给成员变量赋值时,是先给父类赋值的,即使我们初始化列表中子类在前!!!
	//拷贝构造
	//派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化
	Student(const Student& s)
		:_age(s._age),Person(s)//注意这里是切割
	{}
	//赋值重载
	//派生类的operator = 必须要调用基类的operator = 完成基类的复制
	Student& operator=(const Student& s)
	{
		if(this!=&s)
		{
			_age = s._age;
			Person::operator=(s);//注意这里operator函数和父类是隐藏的关系
		}
		else
		{
			exit(-1);
		}
	}
	//析构函数:
	//派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能
	//保证派生类对象先清理派生类成员再清理基类成员的顺序
	//析构先析构子类,构造先构造父类
	~Student()
	{
		//析构子类
		//父类会自动调用的,不用写
	}
protected:
	int _age;
};

五.友元和静态成员

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员
 

此时我们写成友元就可以访问了

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子
类,都只有一个static成员实例
即我们可以通过父类和子类访问同一个静态成员

六.复杂的菱形继承及菱形虚拟继承

单继承:一个子类只有一个直接父类时称这个继承关系为单继承
 

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
 

此时就会出现一种特殊的继承;菱形继承:菱形继承是多继承的一种特殊情况

菱形继承的问题:可以看出菱形继承有数据冗余和二义性的问题。在d的对象中A成员会有两份

此时我们通过限定符去访问A中的成员对象就会出现B和C都可以访问,而且访问的是不同的两个成员,此时就会出现二义性和冗杂
 

此时,C++引入了虚继承的概念。

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在B和C的继承A时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地方去使用。
 

class Person
{
public:
protected:
	string _name; // 姓名
};
class Student : virtual public Person
{
protected:
	int _num; //学号
};
class Teacher : virtual public Person
{
protected:
	int _id; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse; // 主修课程
};

如图,虚继承只需要在:后面写上一个virtual即可,还要注意的是,不同的父类要通过,分隔开

接下来我们深入底层来看看虚继承是如何解决问题的。

菱形继承例子:

这就是一个典型的菱形继承关系

最后,感谢大家的支持!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/478240.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JAVA多线程之线程池

文章目录 1. 线程池状态2. 线程池创建2.1 ThreadPoolExecutor2.2 newFixedThreadPool2.3 newCachedThreadPool2.4 newSingleThreadExecutor2.5 开发要求 3. 提交方法4. 关闭方法5. 任务调度5.1 Timer5.2 Scheduled5.2.1 构造方法5.2.2 schedule5.2.3 scheduleAtFixedRate5.2.4 …

计算机网络——物理层(宽带接入技术)

计算机网络——物理层(宽带接入技术) 什么是宽带有线带宽接入xDSLADSL 技术ADSL 的大部分组成 光纤同轴混合网(HFC 网)机顶盒与电缆调制解调器(set-top box) FTTx 技术光配线网 ODN (Optical Distribution …

最新,955神仙公司名单(非外企)

955 神仙公司名单(非外企) 往常爆料最多的 955 神仙公司名单通常都是集中在一线城市的外企。 例如下面这张最为流行的名单图: 最近牛客网上有同学整理出了非外企的版本,其中不乏一些耳熟能详的互联网产品。 随手把名单分享给大家。…

sonarqube使用指北(二)-如何启动一次完整的本地扫描

一、引言 上一篇文章之后 我们应该已经成功的部署了sonarqube程序,这一篇文章我们就来进行一次简单的本地扫描。 优点: 安全性:你可以在任何你信任的环境下执行扫描工作,而不是依赖外部安全能力即时反馈: 开发者可以在编写代码时获得即时反馈,了解其代码的质量和潜在问题…

机器学习----交叉熵(Cross Entropy)如何做损失函数

目录 一.概念引入 1.损失函数 2.均值平方差损失函数 3.交叉熵损失函数 3.1信息量 3.2信息熵 3.3相对熵 二.交叉熵损失函数的原理及推导过程 表达式 二分类 联立 取对数 补充 三.交叉熵函数的代码实现 一.概念引入 1.损失函数 损失函数是指一种将一个事件&#x…

SW工具下没有URDF

解决方案,下载

阿里云安装宝塔后面板打不开

前言 按理来说装个宝塔面板应该很轻松的,我却装了2天,真挺恼火的,网上搜的教程基本上解决不掉我的问题点,问了阿里云和宝塔客服,弄了将近2天,才找出问题出在哪里,在此记录一下问题的处理。 服…

十分钟快速入门 Python

本文以 Eric Matthes 的《Python编程:从入门到实践》为基础,以有一定其他语言经验的程序员视角,对书中内容提炼总结,化繁为简,将这本书的精髓融合成一篇10分钟能读完的文章。 读完本篇文章后,可对 Python …

【学习】软件测试行业未来的发展趋势预测

近年来,随着中国数字经济的蓬勃发展,软件测试行业也迎来了新的春天。从早期的手工测试到自动化测试,再到持续集成和持续交付,中国的软件测试行业经历了快速的发展和变革。各行各业均对软件测试提出了更高的要求,尤其在…

按摩师C语言

题干出现“接或不接”,“最优”&#xff0c;仔细一想&#xff0c;该用动态规划了。 #include<stdio.h> int max(int a,int b) {if(a>b)return a;elsereturn b; } int massage(int* nums,int numSize) {if(numSize 0)return 0;else if(numSize 1)return nums[0];els…

js 输出负数的个数,和所有正整数的平均值。

首先输入要输入的整数个数n&#xff0c;然后输入n个整数。输出为n个整数中负数的个数&#xff0c;和所有正整数的平均值&#xff0c;结果保留一位小数。 0即不是正整数&#xff0c;也不是负数&#xff0c;不计入计算。如果没有正数&#xff0c;则平均值为0。输入 11 1 2 3 4 5 …

zabbix6.4监控mysql数据库

目录 一、前提二、配置mysql数据库模板三、配置监控的mysql主机 一、前提 已经搭建好zabbix-server 在需要监控的mysql服务器上安装zabbix-agent2 上述安装步骤参考我的上篇文章&#xff1a;通过docker容器安装zabbix6.4.12图文详解&#xff08;监控服务器docker容器&#xf…

2016年认证杯SPSSPRO杯数学建模A题(第二阶段)洗衣机全过程文档及程序

2016年认证杯SPSSPRO杯数学建模 A题 洗衣机 原题再现&#xff1a; 洗衣机是普及率极高的家用电器&#xff0c;它给人们的生活带来了很大的方便。家用洗衣机从工作方式来看&#xff0c;有波轮式、滚筒式、搅拌式等若干种类。在此基础上&#xff0c;各厂商也推出了多种具体方案…

二、Web3 学习(区块链)

区块链基础知识 一、基础知识1. 区块链可以做什么&#xff1f;2. 区块链的三个特点 二、区块链的类型概括1. PoW2. PoS3. 私有链和联盟链 三、智能合约1. 什么是智能合约2. 如何使用智能合约 四、困境1. 三难选择的基本要素2. 这真的是一个三难选择吗? 五、比特币1. 什么是比特…

2024年服装erp系统排名,都有哪些品牌?

随着数字经济时代的到来&#xff0c;传统的服装纺织行业正在经历深刻的变革。如何实现产业数字化升级&#xff0c;是众多服装纺织企业所面临的共同课题。当前&#xff0c;服装erp管理系统已经成为服装企业实现智能化转型的关键&#xff0c;通过将所有流程环节的数据进行统一的信…

C语言字符函数与字符串函数:编织文字的舞会之梦(下)

欢迎来到白刘的领域 Miracle_86.-CSDN博客 系列专栏 C语言知识 先赞后看&#xff0c;已成习惯 创作不易&#xff0c;多多支持&#xff01; 目录 七、strncpy的使用以及模拟实现 八、strncat的使用以及模拟实现 九、strncmp的使用以及模拟实现 十、strstr的使用以及模拟…

预防胜于治疗:六西格玛设计DFSS在新产品开发中的实践

六西格玛设计(Design for Six Sigma, DFSS)是一套旨在从一开始就设计出几乎完美的产品和服务的方法论。它不同于六西格玛改进过程&#xff0c;后者专注于改善现有的产品和流程。DFSS 的核心理念是通过彻底理解顾客需求和采用创新的解决方案来预防缺陷的发生&#xff0c;从而在产…

开源项目ChatGPT-Next-Web的容器化部署(二)-- jenkins CI构建并推送镜像

一、背景 接着上文已制作好了Dockerfile&#xff0c;接下来就是docker build/tag/push等一系列操作了。 不过在这之前&#xff0c;你还必须在jenkins等CI工具中&#xff0c;拉取源码&#xff0c;然后build构建应用。 因为本文的重点不是讲述jenkins ci工具&#xff0c;所以只…

HTTP系列之HTTP缓存 —— 强缓存和协商缓存

文章目录 HTTP缓存强缓存协商缓存状态码区别缓存优先级如何设置强缓存和协商缓存使用场景 HTTP缓存 HTTP缓存时利用HTTP响应头将所请求的资源在浏览器进行缓存&#xff0c;缓存方式分两种&#xff1a;强缓存和协商缓存。 浏览器缓存是指将之前请求过的资源在浏览器进行缓存&am…

山东省大数据局副局长禹金涛一行莅临聚合数据走访调研

3月19日&#xff0c;山东省大数据局党组成员、副局长禹金涛莅临聚合数据展开考察调研。山东省大数据局数据应用管理与安全处处长杨峰&#xff0c;副处长都海明参加调研&#xff0c;苏州市大数据局副局长汤晶陪同。聚合数据董事长左磊等人接待来访。 调研组一行参观了聚合数据展…