C++中的继承(一)

文章目录

  • 前言
  • 概念
  • 访问限定符
  • 基类和派生类的赋值转换
  • 继承中的作用域
  • 派生类的默认成员函数
    • 构造函数
  • 拷贝构造
    • 析构函数
  • 继承的其他一些细节

前言

我们之前说过,继承是面向对象的三大特性。

面向对象的三大特性:
封装、继承、多态。

封装在类和对象体现出。

概念

继承是什么?
继承就是一种类层次的复用,复用就是你的就变成我的.

假设我要实现一个管理系统。
如果按照以前类和对象的方式,单独去实现这个类是很坑的.

每个类都有一些信息, 有些类型之间是有一些共性,
每个类都写,那初始化每个类都要写.
在这里插入图片描述

C++创造了一个语法,可以支持继承,支持什么样的继承呢?
把我们公共的属性提取出来,放到一个类里面去,让剩下的类去继承.
在这里插入图片描述

我们也可以有些单独独立的信息.

继承是什么样的呢?
首先有很多类。如果这些类都有一些公共的特征,那我们就可以这些
类里面有些特性提取出来,专门放到一个类里面。这个类我们叫做父类。

我们想用这些特征,以前我们要写到一起,我们现在可以继承它。
怎么继承?

我们看一下它的语法:

 //基类/父类
class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}

private:  
	string _name = "peter"; // 姓名
	int _age = 18;  // 年龄
};

class Student : public Person
{
protected:
	int _stuid; // 学号
};

继承方式有三种:
公有继承,私有继承,保护继承。

student这个类看起来啥都没有,其实里面啥都有。
在这里插入图片描述

它怎么来的?就是从它的父类。
stuent这个类的信息除了有学生的信息还有pesorn的信息,因为它继承了person.
继承也就是父类的我也有。

访问限定符

继承有三种访问限定符,但这三种访问限定符又有三种访问限定方式。
它们两两组合。
在这里插入图片描述
这些有什么规律?
它们分成了两组规则。
在这里插入图片描述
1.如果是公有成员和保护成员,就取它们继承方式和它的权限里小的那个。(公有大于保护,保护大于私有)
2.私有成员都是不可见。(不可见就是它在这个地方,你不能用)

演示一下,把父类的成员设置成私有
在子类写一个函数。
在这里插入图片描述
在这里插入图片描述
不可见就是在类里面也用不了,但是它跟私有不一样,私有在类里面可以用。

什么时候我们会定义私有呢?
这东西我不想被子类继承就用私有。

私有和保护在子类才有区别

子类能不能调用父类的函数取访问它?
可以。不可见只是指的是不能直接取访问它,取去调用父类的函数去访问也是可以的。

继承方式也可以像访问限定符一样,可以不写,class默认就是私有继承,struct默认就是公有继承。

实际当中用的最多的,就是这些。
在这里插入图片描述

基类和派生类的赋值转换

这是重点中的重点。这块想说的一个问题是什么?
在这里插入图片描述
这里会发生什么?d可以赋值给i吗?
可以。发生隐式类型转换,中间会产生临时变量,临时变量具有常性。

接着往下看,一个子类对象能不能给父类对象呢?
在这里插入图片描述
可以,但是有没有隐式类型转换的发生呢?
这里只适用于公有继承上,子类可以赋值给父类,这个过程叫做赋值兼容转换。
在这里插入图片描述
在这里插入图片描述
怎么证明呢?
在这里插入图片描述

在这里插入图片描述

子类可以赋值给父类,父类能不能给子类?
默认不可以,子类还有一些专有的属性。

继承中的作用域

基类和派生类都有它们独立的作用域。

既然它们都有独立的作用域,那基类和派生类能不能有同名成员呢?
在这里插入图片描述
派生类能不能也定义一个_num,可以。
我们c语言就规定不同的作用域可以定义同名的变量。

但是这样,我是会报错还是会访问派生类的呢?
在这里插入图片描述
理论上是访问派生类的,根据就近原则。
在这里插入图片描述
但是我就想访问基类,有没有什么办法?
指定作用域就可以了,加上域作用限定符。
在这里插入图片描述

子类和父类有同名成员,这种情况我们叫做隐藏或者重定义。
隐藏指的是默认情况下他会隐藏父类的成员。

class Person
{
protected:
	string _name = "小李子"; // 姓名
	int _num = 111; 		// 身份证号
};

class Student : public Person
{
public:
	void Print()
	{
		cout << Person::_num << endl;
		cout << _num << endl;
	}

protected:
	int _num = 999; // 学号
};

这里有个很坑的东西,经常出选择题考。
以下程序哪个是对的。
在这里插入图片描述
这道题的杀手锏是A,为什么是A?
函数名相同,参数不同构成函数重载。
那现在有一个问题,vector里的push_back和list里的push_back呢?
记住,函数重载必须在同一个作用域里面。

编译也没有报错。
虽然它们参数不同,但是它们的关系确实是隐藏。

最麻烦的考法是这样的。
下面这个选什么。
在这里插入图片描述
这道题如果是不定向选择,那就是BC.
如果确实要访问A里的fun, 要指定一下作用域

b.A::func();

结论:
如果是成员函数的隐藏,只需要函数名相同就可以构成隐藏。
不需要考虑参数,不需要考虑返回值。

注意在实际中最好不要定义同名的成员,不然自己坑自己。

派生类的默认成员函数

构造函数

派生类的构造函数时怎么玩的呢?
跟我们以前学的有一点点不一样。
在这里插入图片描述

在这里插入图片描述
注意看这个派生类,我什么都没有写.发生了啥?
如果我们不写,子类会自动调用父类的成员。

如果我们写了呢?
在这里插入图片描述
在这里插入图片描述
不可以。为什么呢?

在派生类当中,规定了,父类的成员,必须调父类的构造函数初始化。
你不写它也会调用父类的,你写他也会调用父类的。
在这里插入图片描述
在这里插入图片描述
上面两个都可以编译通过。
你不写他也会调用父类的默认构造,在初始化列表里调。
继承就像子类把父类当作一个自定义类型的整体成员一样。

那如果父类没有默认构造怎么办?
那我们就必须自己写了,自己显示的调用了。

拷贝构造

拷贝构造和前面也是同样的道理。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以,但是你自己不写他会不会调用父类的拷贝构造。
不会,要初始化父类怎么办?调用父类的拷贝构造。但是要求调用父类的拷贝构造,
是不是要传一个父类的对象过去。

只有子类对象没有父类对象,如何把子类对象父类这一部分拿出来啊。
我们可以用我们之前讲到的切片。
在这里插入图片描述
子类对象我也没有父类的那一部分,但是我可以传过去让它自己切就可以了。
在这里插入图片描述

这里回答一下之前遗留下来的一个问题?
如果是子类对象给父类对象,这个地方是怎么给过去的?
在这里插入图片描述
是memcpy拷贝过去还是怎么拷贝。
这里还是调用了拷贝构造,调用了父类的拷贝构造。
在这里插入图片描述
operatro=也是一样的道理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
但是这里出现了一个栈溢出的问题,是怎么回事呢?
栈溢出一般都是重复调用,这里教大家一个技巧,可以看调用堆栈
在这里插入图片描述
死循环了。为什么?
因为Student类里面的operator=和Person类里面的operator构成隐藏关系。
所以这里自己调用自己了。
在这里插入图片描述
指定作用域就可以了
在这里插入图片描述

在这里插入图片描述

总结一下就是自己干自己的,父类处理父类的。

可不可以不写拷贝构造和赋值呢?
可以,我们之前说过,拷贝构造针对内置类型进行值拷贝或者浅拷贝,
针对自定义类型会调用它的拷贝构造。

析构函数

特点都是先父后子
在这里插入图片描述

在这里插入图片描述

但是有个非常奇怪的现象,我们调用不了析构。为什么?
由于以后多态的原因,析构不会用这个名字,
析构函数会被处理成Destructro,所以它们会构成隐藏的关系。
所以还是指定一下。
在这里插入图片描述
但是这样也不行,父类的析构被调用了两次。
在这里插入图片描述
其它成员函数都可以显示调用,唯独析构函数我们不要显示调用。
它可以自动调用,为什么它可以自动?以为它要保证我们的顺序。
在这里插入图片描述
自己显示写不能保证调用先子后父的顺序。

为什么要先析构子类再析构父类?
因为父类先定义,子类后定义。

先析构父类,再析构子类有可能会出现野指针的问题。
在这里插入图片描述

继承的其他一些细节

友元关系不能被继承。
比如一个类,一个函数是你父类的友元,那是不是你子类的友元呢?
不是。
在这里插入图片描述
但是我就是想访问怎么办?
再定义一个友元就可以了。

class Person
{
public:
	friend void Display(const Person& p, const Student& s);
//protected:
	string _name; // 姓名
};
class Student : public Person
{
	friend void Display(const Person& p, const Student& s);
protected:
	int _stuNum; // 学号
};

void Display(const Person& p, const Student& s)
{
	cout << p._name << endl;
	cout << s._stuNum << endl;
}

void main()
{
	Person p;
	Student s;
	Display(p, s);
}

静态成员是怎么走的?
在这里插入图片描述
在这里插入图片描述

父类继承有一个_count,子类继承会不会也友一个_count呢?
不会。但是从域的角度,子类可以访问它。

无论你继承多少次,都只有一个_count
静态成员变量属于整个类,它不仅属于父类也属于子类。但是只有同一个。

证明一下:
父类当中的_name和子类当中的_name是不是同一个。
不是,它们的地址是不一样的。
但是_count是同一个。

把父类protected:去掉
在这里插入图片描述

下一个问题,这里Peron或者以Peson为继承的子类对象总共创建了多少个对象?
怎么算呢?这里有一个非常巧妙的东西。在父类的构造函数++_count就可以,为什么?
因为子类对象必须调用父类对象去初始化
在这里插入图片描述>

静态的成员所有继承的派生类共享。

实现一个不能被继承的类,如何实现?
最简单的方式就是把它的构造函数私有化,或者析构函数私有化。为什么?
因为构造函数私有了,继承了以后创建不了对象,为什么?
因为子类的构造函数必须去调用父类的构造函数,而父类的构造函数私有,子类调用不了。
在这里插入图片描述
A的构造函数私有,B是无论如何也调用不了。
A怎么调用呢?A是有办法的。

class A
{
public:
	static A CreateObj()
	{
		return A();
	}
private:
	A()
	{}
};
class B : public A
{};
int main()
{
//要调用函数首先要创建对象
//我们可以用静态成员函数,就可以直接用类去调用它
	A::CreateObj();
	return 0;
}

友元是能不用就不用。

其实C++正常的继承学到这里也差不多了,但是还有一个大坑,我们留到下篇文章

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

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

相关文章

【unity小技巧】最简单的FPS游戏准心跳动动画控制

最终效果 文章目录 最终效果前言绘制简单的准心UI实现不同状态准心大小变化射击准心跳动的效果完结 前言 游戏准心跳动在FPS也是比较常用的功能&#xff0c;可以增强游戏反馈和打击感&#xff0c;丰富游戏内容&#xff0c;实现准心跳动的方式五花八门&#xff0c;我不知道别人…

Redis Streams 实现消息队列

简单介绍 Redis中有三种消息队列模式&#xff1a; 可以看出&#xff0c;作为Redis 5.0 引入的专门为消息队列设计的数据类型&#xff0c;Stream 功能更加健全&#xff0c;更适合做消息队列分发。 Stream 可以包含 0个 到 n个元素的有序队列&#xff0c;并根据ID的大小进行排序…

【CMU 15-445】Lecture 10: Sorting Aggregations Algorithms 学习笔记

Sorting & Aggregations Algorithms SortingTop-N Heap SortExternal Merge Sort2-WAY External Merge SortK-WAY External Merge SortDouble Buffering Optimization AggregationsSortingHashing 本节课主要介绍的是数据库系统中的排序算法以及聚合算法 Sorting 排序算法…

数据结构期末考题之001

算法复杂度就是n&#xff08;0&#xff09;

JdbcTemplate

环境搭建 依赖 <!-- Oracle11g 连接驱动依赖。这里是个坑&#xff0c;官方提供的不能用 --><dependency><groupId>cn.easyproject</groupId><artifactId>ojdbc6</artifactId><version>12.1.0.2.0</version></dependency&g…

20231217在Canonical 官网下载ubuntu-20.04.6以及通过rufus-4.3p写入U盘作为安装盘

20231217在Canonical 官网下载ubuntu-20.04.6以及通过rufus-4.3p写入U盘作为安装盘 2023/12/17 11:45 百度搜索&#xff1a;https://ubuntu.com/ https://ubuntu.com/engage/migrating-from-rhel-centos-to-ubuntu-public-cloud?utm_sourcetakeover http://releases.ubuntu.co…

从关键新闻和最新技术看AI行业发展(2023.12.4-12.17第十二期) |【WeThinkIn老实人报】

写在前面 【WeThinkIn老实人报】旨在整理&挖掘AI行业的关键新闻和最新技术&#xff0c;同时Rocky会对这些关键信息进行解读&#xff0c;力求让读者们能从容跟随AI科技潮流。也欢迎大家提出宝贵的优化建议&#xff0c;一起交流学习&#x1f4aa; 大家好&#xff0c;我是Rock…

软件设计规约和评审

软件设计规约 概要设计规约&#xff1a;这是面向软件开发者的文档&#xff0c;主要作为软件项目管理人员、系统分析人员与设计人员之间交流的媒介。它指明了软件的组织结构&#xff0c;主要内容包括&#xff1a; 系统环境&#xff1a;硬件、软件接口与人机界面&#xff1b;外部…

半导体设备之外延炉简述

半导体设备对整个半导体行业起着重要的支撑作用。因半导体制造工艺复杂&#xff0c;各个环节需要的设备也不同&#xff0c;从流程工序分类来看&#xff0c;半导体设备主要可分为晶圆制造设备&#xff08;前道工序&#xff09;、封装测试设备&#xff08;后道工序&#xff09;等…

自动驾驶学习笔记(二十)——Planning算法

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo 社区开发者圆桌会》免费报名—>传送门 文章目录 前言 参考线平滑 双层状态机 EM Planner …

724. 寻找数组的中心下标

代码&#xff1a; class Solution {public int pivotIndex(int[] nums) {int last0; //放前一个下标的左右差值int now0; //放当前下标的左右差值// 0 位于边界&#xff0c;先算出 0 下标左右的差值for(int i1;i<nums.length;i){lastnums[i];}//判断是否 0 下标就已…

大模型自定义算子优化方案学习笔记:CUDA算子定义、算子编译、正反向梯度实现

01算子优化的意义 随着大模型应用的普及以及算力紧缺&#xff0c;下一步对于计算性能的追求一定是技术的核心方向。因为目前大模型的计算逻辑是由一个个独立的算子或者说OP正反向求导实现的&#xff0c;底层往往调用的是GPU提供的CUDA的驱动程序。如果不能对于整个计算过程学习…

Ubuntu 常用命令之 cp 命令用法介绍

cp命令在Ubuntu系统中用于复制文件或目录。它的基本格式是cp [选项] 源文件或目录 目标文件或目录。 以下是一些常用的cp命令选项 -i&#xff1a;在覆盖目标文件之前将给出提示。-r或-R&#xff1a;递归复制&#xff0c;用于目录的复制操作。-v&#xff1a;详细模式&#xff…

地平线前端实习一面复盘(加深对var的理解+展开运算符+平拍数组)

目录 前言一&#xff0c;var的作用二&#xff0c;展开运算符三&#xff0c;平拍数组总结 前言 地平线的面试&#xff0c;有提示&#xff0c;很专业&#xff0c;体验很好。 可惜后面未收到消息&#xff0c;但还是要做复盘。收获还是很大的。 一&#xff0c;var的作用 且看下…

MySQL中EXPLAIN执行计划的分析

一. 执行计划能告诉我们什么&#xff1f; SQL如何使用索引联接查询的执行顺序查询扫描的数据函数 二. 执行计划中的内容 SQL执行计划的输出可能为多行&#xff0c;每一行代表对一个数据库对象的操作 1. ID列 ID列中的如果数据为一组数字&#xff0c;表示执行SELECT语句的顺…

网络基础(十二):ACL与NAT

目录 一、ACL 1、ACL的概述 2、ACL的分类 3、ACL的应用 4、ACL的组成和基本原理 ​编辑 5、ACL的配置 5.1配置基本ACL 5.2配置高级ACL 二、NAT 1、NAT的概述 2、NAT的分类 3、NAT的工作原理 4、静态NAT的配置 5、动态NAT的配置 6、NAPT&#xff08;端口映射&am…

自动驾驶技术:驶向未来的智能之路

导言 自动驾驶技术正引领着汽车产业向着更安全、高效、智能的未来演进。本文将深入研究自动驾驶技术的核心原理、关键技术、应用场景以及对交通、社会的深远影响。 1. 简介 自动驾驶技术是基于先进传感器、计算机视觉、机器学习等技术的创新&#xff0c;旨在实现汽车在不需要人…

论文降重系统同义词替换功能的改进方向 快码论文

大家好&#xff0c;今天来聊聊论文降重系统同义词替换功能的改进方向&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 标题&#xff1a;论文降重系统同义词替换功能的改进方…

java21特性学习

jdk21下载地址 JDK21文件 JDK21是javaSE平台最新的长期支持版本。 Java SE Java Archive | Oracle JDK21版本说明 JDK 21 Release Notes, Important Changes, and Information JavaSE 版本字符串格式 Version-String Format JavaSE平台采用了基于时间的发布模型,JDK每六个…

虚拟化之安全虚拟化

虚拟化首次引入是在Armv7-A架构中。那时&#xff0c;Hyp模式&#xff08;在AArch32中相当于EL2&#xff09;仅在非安全状态下可用。当Armv8.4-A引入时&#xff0c;添加了对安全状态下EL2的支持作为一个可选特性。 当处理器支持安全EL2时&#xff0c;需要使用SCR_EL3.EEL2位从E…