yo!这里是c++中的继承

news2025/1/22 8:10:07

目录

前言

概念定义

基类与派生类对象转换

作用域

派生类的默认成员函数

与友元&&与静态成员

菱形继承及菱形虚拟继承

多继承

菱形继承

虚拟继承

1.介绍

2.原理

继承总结

后记


前言

        封装、继承、多态作为c++的三大特性,在学完封装的有关内容之后,今天来学习学习继承相关内容,涉及到作用域、派生类的默认成员函数、与友元关系、与静态成员关系及菱形继承等,这些内容也是在面试过程中的高频问点,将相关内容一学习,加上左后的总结归纳,继承的相关知识点就不成问题,快往下看看吧。

概念定义

        C++中的继承是指派生类继承基类的特性和功能。派生类可以访问基类的非私有成员变量和成员函数,并且可以在派生类中添加自己的成员变量和成员函数,从而扩展基类的功能,比如对于下面的例子,Person类是一个人的类型,基本属性有姓名、年龄等,但这个人可以具体到是个学生(也可以是老师,老板等),除了人的特性以外,还应该具有其他属性,比如学号等,此时这个学生类不仅有人类型的成员,还有属于一个学生独有的成员。

        继承可以分为公有继承、私有继承和保护继承三种形式,它们的访问权限限定了派生类对基类成员的访问情况,具体如下图所示。总的来说,继承是C++中的一个重要概念,它可以提高代码的复用性和可维护性,减少代码冗余。

注意:

        ①基类的private成员在派生类中无论以什么方式继承都是不可见的,不可见就是类内外都不可访问;

        ②在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,所以,想可以在类外访问就基类成员写成public,不想可以类外访问,基类成员就写protected;

        ③在基类(或者单独的一个类)中,protected与private并无区别,都是类内可访问,类外不可访问,区别在继承中的子类中才会体现,比如对于public继承方式,protected成员还是protected,但private成员变成不可见。

eg:

class People
{
protected:
	string _name;
	int _age;
};

class Student : public People
{
protected:
	int _stuid;
};

基类与派生类对象转换

        前提在public继承方式下,派生类的对象 / 指针 / 引用可以赋值给基类的对象 / 指针 / 引用,叫切片或者切割,意思就是把派生类中父类那部分切割下来赋值过去,如下图一。

        注意:反之不可以,即基类对象不能赋值给派生类对象,如下图二。

eg:

作用域

        在继承体系中,基类和派生类都有独立的作用域,所以可以有同名成员;若在子类和父类中有同名成员,子类将屏蔽父类中的同名成员的直接访问,这种情况叫隐藏(也叫重定义),但在子类成员函数中,可以通过使用【基类::基类成员】显式访问,不指明类域的默认是子类的成员。

注意:

        ①如果是成员函数的隐藏,只需要函数名相同就构成隐藏

        ②在实际中,继承体系里面最好不要定义同名的成员;

        ③在继承体系中,函数名相同不可能是重载关系,因为它们不在同一作用域。

eg:

派生类的默认成员函数

1)构造函数

        构造函数一般不用自动生成的,而是用自己显式实现的,因为可以通过初始化列表初始化成员,所以必须知道,派生类对象初始化先调用基类构造函数初始化基类的那一部分成员,再调派生类构造函数初始化剩下的成员,如果基类没有默认构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。

        如下代码,基类的构造函数正常像以往一样实现,对于派生类,一方面可以传入想要的基类和子类的成员的值,通过初始化列表初始化(注意初始化基类成员的写法),另一方面也可以只传入自己的成员的值在初始化列表初始化,而基类的成员就会调用基类的默认构造函数初始化。

代码:

//基类
class People
{
	People(string name = "未知", int age = 0)
		:_name(name)
		, _age(age)
	{

	}
protected:
	string _name;
	int _age;
};

//派生类
class Student : public People
{
public:
    //Student(int stuid = 0)
	Student(string name = "未知", int age = 0, int stuid = 0)
		:People(name, age)
		,_stuid(stuid)
	{

	}
}

 2)拷贝构造函数&&赋值操作符重载

        派生类对象的拷贝构造函数必须调用基类的拷贝构造函数完成基类成员的拷贝,即通过切片的方式将基类部分传给目标对象的基类部分,再用初始化列表初始化派生类部分成员。

        而赋值操作符重载的实现也是一样,只是不能通过初始化列表,必须在函数体内赋值,先调用基类的赋值操作符重载函数赋值基类部分的成员,再赋值剩下派生类部分成员。

代码: 

	//显式实现拷贝构造(不写也可以,有申请的空间时需要自己写,因为需要深拷贝)
	Student(const Student& s)
		:People(s)   //切片
		, _stuid(s._stuid)
	{

	}

	//显式实现赋值操作符重载(不写也可以)
	Student& operator=(const Student& s)
	{
		if (this != &s)
		{
			People::operator=(s);  //构成隐藏&&切片
			_stuid = s._stuid;
		}
		return *this;
	}

3)析构函数

        派生类对象析构清理先调用派生类的析构函数再调基类的析构函数。所以,应该先释放派生类中申请空间的成员(如果有的话),再调用基类的析构函数People::~People()。

        但这里为什么~Student()和~People()不同名不构成隐藏,还要加上People::?

        因为后面多态的需要,父子类的析构函数名会被编译器统一为destructor(),导致同名,所以子类的析构函数和父类的析构函数构成隐藏

        但为什么又注释掉了People::~People(),即不需要调用父类的析构函数?
        因为在每个子类析构函数后面编译器会自动调用父类析构函数,保证“先构造的后析构”的顺序(即先构造的父类,再构造的子类,所以要先析构子类,再析构父类),不然代码实现会容易搞反顺序,所以不需要显示调用父类析构函数。

	//显式实现析构函数(不写也可以)
	~Student()
	{
		//People::~People();
	}

与友元&&与静态成员

1)与友元

        友元关系不能继承,即作为基类的友元,可以访问基类的私有和保护成员,但并不能访问子类的私有和保护成员。

2)与静态成员

        当基类中定义了一个静态成员,则整个继承体系中都只有这一份,即无论派生出多少个子类,都只有这一个静态成员。

eg1):

eg2):

菱形继承及菱形虚拟继承

  • 多继承

        按照以往写的,一个子类只有一个直接父类时称这个继承关系为单继承(如图一),而一个子类有两个或以上直接父类时称这个继承关系为多继承(如图二)。

  • 菱形继承

        菱形继承是多继承的一种特殊情况,是一种对象模型中的问题,指的是当一个类同时继承自两个不同的类,而这两个类又各自继承自同一个父类时,就会形成一个类似于菱形的继承结构,如图。

        那菱形继承存在什么问题呢?从上图可以看出,D类型的对象中会有两份A的成员,存在数据冗余,同时又存在二义性问题。

        而二义性问题很好解决,只需要去指定访问哪个类的成员即可,比如

        但数据冗余问题又如何解决呢?所以这个方法并不完善,有无一个方法直接一下解决这两个问题?下面就要引出虚拟继承的概念了。

  • 虚拟继承

1.介绍

        虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在B和C继承A时使用虚拟继承,即在中间两个类实现上加上virtual关键字,如下图。值得注意的是,虚拟继承不要在其他地方去使用,目前只用在解决菱形继承上。

2.原理

        先来看看改为虚拟继承前后的D的内存对象成员模型,如下图。

        改为虚拟继承前,B、C拥有各自的A成员,改为虚拟继承后,B、C类中除了存储自己的成员之外,还会有一个虚基表指针指向一个虚基表,这个虚基表中,前四个字节存储的是0,下面四个字节存储的就是A相对于自己的一个偏移量(字节为单位),根据偏移量就能算出A类型的位置,比如B的虚基表中偏移量为20,可以知道0x012FFD08+20=0x012FFD1C为A的位置,进而得到A类成员。值得注意的是,偏移量找到的并不是A的某个成员,而是顺着地址找到整个A类成员。

继承总结

        从多继承可以看出,继承是C++一个比较复杂的知识点,在其之后的语言都舍弃了这个语法,虽复杂,但场景适合的时候也是可以用的,这里说一下继承和组合之间的区别与联系。

        public继承是一种is-a的关系,也就是说每个派生类对象都是一个基类对象;组合是一种has-a的关系,即每个B对象中都有一个A对象成员,如下图。

        在一个场景中,当两个关系都可以使用时,优先使用对象组合,而不是类继承。而且实际中,尽量多去用组合,因为组合的耦合度低,代码维护性好。不过继承用处也是很多的,有些关系就适合继承那就用继承,另外在实现多态中,也必须要继承。

后记

        继承中存在不少的面试高频考点,但也存在许多缺陷或者不必要有的东西,比如多继承、菱形继承等,使得c++变得很复杂,但c++毕竟是第一个“吃螃蟹的人”,这也造就了c++的经典之处,这些缺陷在后来的众多语言中都被舍弃。既然我们选择学习c++,那么我们不能区别对待,只要面试中会问到的东西我们就要去了解,而且继承也是后面多态的前提基础,以上就是继承涉及到的相关知识点,记得反复观看,加油,拜拜!


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OAuth2.0二 JWT以及Oauth2实现SSO

一 JWT 1.1 什么是JWT JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简介的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JW…

python借助isinstance(item, (int, float))提取列表中的数字

如下一个列表[1,2,3,23, ,123] 借助isinstance(item, (int, float)) List [1,2,3,23, ,123] numbers [] # 遍历原始列表 for item in List:# 检查每个元素是否为数字(整数或浮点数)if isinstance(item, (int, float)):# 如果是数字,则添加…

Eclipse的安装(NEW~)

艾米,我擅长做很多事,但忘记你你并非其中一件。 随着IntelliJ IDEA在Java开发领域越来越广泛的被使用,Eclipse似乎快要退出舞台了。不过作为一款开源免费并拥有悠久历史的Java 开发IDE,总会有一批铁粉支持它,惦记着它。…

Ubuntu 20.04 LTS 安装Kubernetes 1.26

1、环境配置 (1)添加主机名称解析记录 cat > /etc/hosts << EOF 192.168.44.200 master01 master01.bypass.cn 192.168.44.201 node01 node01.bypass.cn 192.168.44.202 node02 node02.bypass.cn EOF(2)禁止K8s使用虚拟内存 swapoff -a sed -ri s(.*swap.*)#\1…

新手入门C语言安装IDE教程(以CLion,CodeBlocks,小熊猫)

前言 当时自己入门c语言时候老师让使用codeblocks&#xff0c;但是这玩意过于离谱了。 所以如果不是强求的话还是不建议codeblocks 个人推荐&#xff1a; 新手期刚学c语言: 可以先用用小熊猫c&#xff08;汉化版的devcpp&#xff09;然后下载个CLion&#xff08;Vscode你要是…

分享码云上8个宝藏又有价值的开源图片编辑器

如果你需要高效地处理图片&#xff0c;那么这8款实用工具是可以尝试的&#xff01; 它们能够进行一键抠图、放大、拼接、转矢量图、图标自动生成以及等操作&#xff0c;让你的工作效率飞升&#xff01; 在Gitee这个最有价值的开源项目计划是Gitee综合评定出的优秀开源项目的展示…

ModaHub魔搭社区——未来向量数据库会不像传统数据库那样,在国内涌现 200 多家出来?

I. 引言:数据库市场的持续扩张与向量数据库的崛起 随着技术的迭代速度越来越快,技术门槛也在逐渐降低,数据库市场的持续扩张是不可避免的。当前存在着大量的需求,这将吸引越来越多的数据库甚至向量数据库加入竞争。然而,从业界角度看,这种市场扩张是有利的。它可以促使更…

【人工智能】—_维度灾难、降维、主成分分析PCA、获取旧数据、非线性主成分分析

文章目录 高维数据与维度灾难维度灾难降维为什么需要降维&#xff1f;PRINCIPLE COMPONENT ANALYSIS主成分的几何图像最小化到直线距离的平方和举例主成分的代数推导优化问题计算主成分&#xff08;Principal Components, PCs&#xff09;的主要步骤获取旧数据的方法&#xff1…

计算一组数据中的低中位数即如果一组数据中有两个中位数则较小的那个为低中位数statistics.median_low()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 计算一组数据中的低中位数 即如果一组数据中有两个中位数 则较小的那个为低中位数 statistics.median_low() 选择题 以下程序的运行结果是? import statistics data_1[1,2,3,4,5] data_2[1,2,…

IIR滤波器

IIR滤波器原理 IIR的特点是&#xff1a;非线性相位、消耗资源少。 IIR滤波器的系统函数与差分方程如下所示&#xff1a; 由差分方程可知IIR滤波器存在反馈&#xff0c;因此在FPGA设计时要考虑到有限字长效应带来的影响。差分方程中包括两个部分&#xff1a;输入信号x(n)的M节…

LLM学习笔记(1)

学习链接 ChatGPT Prompt Engineering for Developers - DeepLearning.AI 一、prompt engineering for developer 1、原则 prompting principles and iterative pattern 2、用于summarize 环境与helper functions import openai import osfrom dotenv import load_dotenv…

C语言深入理解指针(非常详细)(二)

目录 指针运算指针-整数指针-指针指针的关系运算 野指针野指针成因指针未初始化指针越界访问指针指向的空间释放 如何规避野指针指针初始化注意指针越界指针不使用时就用NULL避免返回局部变量的地址 assert断言指针的使用和传址调用传址调用例子&#xff08;strlen函数的实现&a…

MySQL 8.0.34安装教程

一、下载MySQL 1.官网下载 MySQL官网下载地址&#xff1a; MySQL :: MySQL Downloads &#xff0c;选择下载社区版&#xff08;平时项目开发足够了&#xff09; 2.点击下载MySQL Installer for Windows 3.选择版本8.0.34&#xff0c;并根据自己需求&#xff0c;选择下载全社区安…

2023开学礼新疆石河子大学图书馆藏八一新书《乡村振兴战略下传统村落文化旅游设计》许少辉新财经理工

2023开学礼新疆石河子大学图书馆藏八一新书《乡村振兴战略下传统村落文化旅游设计》许少辉新财经理工

监控服务器与Zabbix服务器时间同步配置

一、简介 zabbix server数据采集对时间同步的要求比较高&#xff0c;因为被监控的主机时间快了&#xff0c;会导致数据读取失败等问题&#xff0c;时间慢了&#xff0c;会有一堆的因为数据写入延时产生的误告警&#xff0c;会发生告警恢复时间比告警产生时间早的情况。此案列以…

CSS中如何实现文字渐变色效果(Text Gradient Color)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 文字渐变色效果&#xff08;Text Gradient Color&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这…

MIT6.824 Spring2021 Lab 1: MapReduce

文章目录 0x00 准备0x01 MapReduce简介0x02 RPC0x03 调试0x04 代码coordinator.gorpc.goworker.go 0x00 准备 阅读MapReduce论文配置GO环境 因为之前没用过GO,所以 先在网上学了一下语法A Tour of Go 感觉Go的接口和方法的语法和C挺不一样, 并发编程也挺有意思 0x01 MapRed…

Navicat16安装教程

注&#xff1a;因版权原因&#xff0c;本文已去除破解相关的文件和内容 1、在本站下载解压后即可获得Navicat16安装包和破解补丁&#xff0c;如图所示 2、双击“navicat160_premium_cs_x64.exe”程序&#xff0c;即可进入安装界面&#xff0c; 3、点击下一步 4、如图所示勾选“…

Delphi 12 β版新增两个有用功能

目录 一、字符串长度允许超过255 二、新增多字符串功能 一、字符串长度允许超过255 现在&#xff0c;字符串字面量的长度可以超过 255 个字符&#xff1b;换句话说&#xff0c;字符串字面量不再局限于经典的 Pascal ShortString 类型。注意字面字符串的长度仍可能受到编辑器的…

一文读懂强化学习:RL全面解析与Pytorch实战

目录 一、引言强化学习的核心组成为什么强化学习重要&#xff1f;实用性与广泛应用自适应与优化推动AI研究前沿引领伦理与社会思考 二、强化学习基础马尔可夫决策过程&#xff08;MDP&#xff09;状态&#xff08;State&#xff09;动作&#xff08;Action&#xff09;奖励&…