当前位置: 首页 > news >正文

C++ - 继承

继承的基本概念

继承就是一种代码的复用.
子类通过继承父类, 就能使用父类的变量, 方法.

学生和老师这两种身份, 他们都有共同的属性: 他们都有名称, 年龄, 性别 ....

当然他们也有各种独有的属性, 学生有学号, 老师有工号 ....

对于这些共有的属性, 我们可以将它们提取出来:

class person
{public:string name;string sex;int age;
};

然后让学生类和老师类去继承这个 person 类.

class student : public person
{
public:string student_ID; // 学号
};
class teacher : public person
{
public:string job_ID;
};

class student : public person

student: 派生类 (又称为子类)

public: 继承方式

person: 基类 (又称为父类)

现在实例化出一个 student 对象之后, 这个对象也有 person 中的属性.

student st;
st.name = "张三";
st.age = 14;
st.student_ID = "123456";

继承关系和访问限定符

C++ 中存在三种访问限定符

  • private: 只能在类内访问
  • protected: 允许类内和派生类 (子类) 访问
  • public: 无论类内类外都可以访问

那么当这三种访问限定符用在继承中, 有什么样的效果.

子类继承父类时, 会继承父类的成员属性和成员方法.
继承存在自己的继承关系 (private ...), 属性和方法也有自己的访问修饰限定符.
这两者之间的关系是如何的呢?

结论: 取 继承关系的限定符 和 访问修饰限定符中, 权限小的那一个

class person
{
public:int a;
protected:int b;
public:int c;
};// 1. public 继承
class student1 : public person
{//父类所有的属性都会被继承
public:int a;
protected: // protect 和 public 取权限小的那一个int b;
};// 2. private 继承
class student2 : private person
{
private: // private 和 public 取权限小的那一个int a;
private:int b;
};

我们可以看到, 继承得到的属性和方法的访问限定符, 是取二者之间较小的那一个.

但是在上面的两个继承的 student 类中, 我没有将变量 c 写出来, 这是为什么?
很简单, 变量 c 由 private 修饰, 所以只能在 person 中访问, 即便 student 继承了 person,
student 是独立的, 不是 person 的一部分, 也就无法访问 c.

一般而言, 都是使用 public 继承.

这里用一张图来表明继承后的方法和属性的访问权限

 继承的作用域

从上面的成员的继承, 我们能察觉到, 派生类和基类是两个不同的空间.

那么既然是不同的空间, 在派生类中, 就可以定义和父类一样的成员属性和成员方法.

class person
{
public:int add(int a, int b){}string name;int age;
};class student : public person
{
public:int add(){return person::add(10, 20);}string name;
};student st;
st.name; // 就近原则, 默认访问子类的
st.person::name; // 带上基类的作用域, 才会访问到基类的属性

在同一个作用域中, 是不能存在两个同名变量的, 但是派生类和基类是不同的作用域. 他们的作用域都是独立的.
所以, 在派生类和基类中定义名称相同的变量也是可以的. (但是在实际使用中, 是不推荐这样写的)

那么这里就有一个很容易犯错的点. 上面代码中的 add 函数, 是不是构成了重载?
当然不是, 重载的条件之一就是: 同名函数处于同一作用域, 派生类和基类属于不同作用域.
当然也就不构成重载. 

事实上, 这种情况称为隐藏 (也成为重定义). 在子类成员函数中,可以使用 基类::基类成员 访问.

父子类的对象赋值转换

  • 子类对象赋值给基类的 对象/基类指针/基类引用
  • 父类对象不能赋值给派生类对象

因为子类拥有父类的所有属性和方法, 父类赋值给子类, 就是把子类中, 父类的那部分给切出来.

这个过程称为"切片".

子类中的默认成员函数

  • 子类的构造/拷贝构造/赋值重载函数, 都需要去调用父类的构造/拷贝构造/赋值重载.
  • 子类的析构函数, 会自动的调用父类的析构函数, 所以不用显示的写出来
  • 当实例化一个子类对象时, 会先初始化父类的成员变量, 然后再初始化子类的成员变量
  • 当析构一个子类对象时, 会先调用子类的析构函数, 然后再调用父类的析构函数. (与构造函数调用顺序相反)

下面代码可以通过打印顺序观察各自的调用顺序.

class person
{
public:person(const char* name = "parent"):_name(name){cout << "person()" << endl;}person(const person& p){_name = p._name;cout << "person(const person&)" << endl;}person& operator= (const person& p){cout << "person operator=" << endl;if(this != &p){_name = p._name;}return *this;}~person(){cout << "~person()" << endl;}
private:string _name
};class student : public person
{
public:student(const char* name, int age):person(name),_age(age){cout << "student()" << endl;}student(const student& st):person(s),_age(st._age){}student& operator= (const student& st){cout << "student operator=" << endl;person::operator=(st);_age = st._age;return *this;}~student(){cout << "~student" << endl;}
private:int _age;
};int main()
{student s1("zhangsan", 10);student s2(s1);student s3("lisi", 20);s1 = s3;return 0;
}

菱形继承和虚继承

在C++中, 允许一个派生类继承多个基类, 这样会导致一个问题.

那么此时问题来了, D同时继承了 B和C, B和C 都继承了A.
那么D中就存在两份类A的成员属性, 一份来自B, 一份来自C.

此时D中就多余了一份数据, 占用了额外的空间.
更重要的是, 造成了二义性. 当我们访问继承至类A的属性时,
访问的是通过B继承得来的, 还是通过继承C得来的. 无法区分.

所以这里就引出了一个方法来解决这个菱形继承的问题.

虚继承: 在 B, C 继承前加上 virtual 关键字.

class A
{int a;
};class B : virtual public A
{int b;
};class C : virtual public A
{int c;
};class D : public B, A
{int d;
};

virtual 关键字要加在 B, C前, 而不是 D 前.

在实际写代码中, 是很少会使用多继承的, 这样带来的不可控影响太大了.
所以在实际写代码中, 能不用多继承就不用多继承. 这部分了解即可

相关文章:

C++ - 继承

继承的基本概念 继承就是一种代码的复用. 子类通过继承父类, 就能使用父类的变量, 方法. 学生和老师这两种身份, 他们都有共同的属性: 他们都有名称, 年龄, 性别 .... 当然他们也有各种独有的属性, 学生有学号, 老师有工号 .... 对于这些共有的属性, 我们可以将它们提取出来: …...

华为服务器使用U盘重装系统

一、准备工作 下载官方系统&#xff08;注意服务器CPU的架构是x86-64还是aarch64&#xff0c;不然可能报意想不到的错&#xff09;制作启动U盘&#xff08;下载rufus制作工具&#xff0c;注意文件系统选FAT32还是NTFS&#xff09; 二、安装步骤 将U盘插入USB接口重启服务器…...

网络分层模型( OSI、TCP/IP、五层协议)

1、网络分层模型 计算机网络是一个极其复杂的系统。想象一下最简单的情况&#xff1a;两台连接在网络上的计算机需要相互传输文件。不仅需要确保存在一条传输数据的通路&#xff0c;还需要完成以下几项工作&#xff1a; 发起通信的计算机必须激活数据通路&#xff0c;这包括发…...

前端开发 之 15个页面加载特效上【附完整源码】

文章目录 一&#xff1a;彩球环绕加载特效1.效果展示2.HTML完整代码 二&#xff1a;跷跷板加载特效1.效果展示2.HTML完整代码 三&#xff1a;两个圆形加载特效1.效果展示2.HTML完整代码 四&#xff1a;半环加载特效1.效果展示2.HTML完整代码 五&#xff1a;音乐波动加载特效1.效…...

Spring Boot使用JDK 21虚拟线程

JDK 21引入的虚拟线程&#xff08;Virtual Threads&#xff09;是 Project Loom 的一部分&#xff0c;旨在显著简化并发编程并提高 Java 应用的可扩展性。以下是虚拟线程的主要特点&#xff1a; 1. 概念 虚拟线程是轻量级线程&#xff0c;与传统的操作系统线程不同&#xff0…...

《从0到1常用Map集合核心摘要 + 不深不浅底层核心》

《从0到1常用Map集合核心摘要不深不浅底层核心》 前置知识 什么是键值对 ​ 键值对是一种数据结构&#xff0c;键是唯一标识&#xff0c;值是对应数据&#xff0c;用来快速查找信息。例&#xff1a; {"name": "Alice"}&#xff0c;键是name&#xff0c;…...

12 设计模式之工厂方法模式

一、什么是工厂方法模式&#xff1f; 1.定义 在软件开发中&#xff0c;设计模式 是解决常见软件设计问题的最佳实践。而 工厂方法模式&#xff08;Factory Method Pattern&#xff09; 作为创建型设计模式之一&#xff0c;常常被用来解决对象创建问题。它通过将对象的创建交给…...

spaCy 入门与实战:强大的自然语言处理库

spaCy 入门与实战&#xff1a;强大的自然语言处理库 spaCy 是一个现代化、工业级的自然语言处理&#xff08;NLP&#xff09;库&#xff0c;以高效、易用和功能丰富著称。它被广泛应用于文本处理、信息提取和机器学习任务中。本文将介绍 spaCy 的核心功能&#xff0c;并通过一…...

python包的管理和安装——笔记

1.列出包 pip list pip freeze 用这2个可以查看当前python 下所有的包和版本&#xff0c;还有下载地址 如果只是想导出当前的环境 可以用 2.安装pipreqs pip install pipreqs&#xff0c;pipreqs ./可以导出当前项目的包这个包 遇到编码报错 pipreqs ./ --encodingutf8 p…...

Vue前端页面内嵌套本项目iframe窗口的通信传输方式

一、目的 想要在iframe中使用本项目页面、并能够与其父页面组件实现实时通信。Vue前端页面内嵌套本项目iframe窗口的通信传输方式-星林社区 https://www.jl1mall.com/forum/PostDetail?postId20241202172800023969 二、iframe通信方式 1.接收消息 页面需要监听 message 事件…...

【WEB开发.js】addEventListener事件监听器的绑定和执行次数的问题(小心踩坑)

假设我们有一个按钮&#xff0c;用户点击该按钮后&#xff0c;会选择一个文件&#xff0c;且我们希望每次点击按钮时只触发一次文件处理。下面我会给你一个简单的例子&#xff0c;展示放在函数内部和放在函数外部的区别。 1. 将事件监听器放在函数内部&#xff08;问题的根源&…...

用于LiDAR测量的1.58um单芯片MOPA(一)

--翻译自M. Faugeron、M. Krakowski1等人2014年的文章 1.简介 如今&#xff0c;人们对高功率半导体器件的兴趣日益浓厚&#xff0c;这些器件主要用于遥测、激光雷达系统或自由空间通信等应用。与固态激光器相比&#xff0c;半导体器件更紧凑且功耗更低&#xff0c;这在低功率供…...

【GPT】代谢概念解读

以下是对代谢中分解代谢和合成代谢两个概念的深入解读&#xff0c;用简单易懂的方式展开说明&#xff1a; 1. 分解代谢&#xff08;Catabolism&#xff09; 什么是分解代谢&#xff1f; 分解代谢是身体把大分子“拆开”的过程。就像把一个三明治分解成面包片、肉片和菜叶&#…...

Devops-git篇-01-git环境配置

环境配置 设置用户签名 配置用户名&#xff1a; git config --global user.name 你的用户名 配置邮箱&#xff1a; git config --global user.email 注册的邮箱 配置好之后&#xff0c;可以用git config --global --list命令查看配置是否OK $ git config --global --list u…...

STM32 HAL库开发学习1.STM32CubeMX 新建工程

STM32 HAL库开发学习1.STM32CubeMX 新建工程 一、 STM32 CubeMX 下载二、CubeMX 功能介绍1. 固件包路径设置2. 新建工程 三、创建项目实例1. 新建项目2. GPIO 管脚设置3. GPIO 窗口配置4. 调试设置5. 时钟配置6. 项目管理&#xff08;1&#xff09;项目信息&#xff08;2&#…...

JS学习(2)(浏览器执行JS过程、JS的ECMAScript、DOM、BOM)

目录 一、浏览器如何执行JS&#xff1f; &#xff08;1&#xff09;浏览器主要的组成部分。 1、渲染引擎。 2、JS引擎。 &#xff08;2&#xff09;演示。 二、JS的组成。 &#xff08;1&#xff09;JS主要由三部分组成。 1、JS基础。 2、JS-API。 &#xff08;2&#xff09;EC…...

如何解决服务器扫描出的ASP木马问题

随着互联网的发展&#xff0c;网站安全问题日益凸显。其中&#xff0c;ASP&#xff08;Active Server Pages&#xff09;木马因其隐蔽性和危害性成为攻击者常用的手段之一。本文将详细介绍如何检测和清除服务器上的ASP木马&#xff0c;以保障网站的安全。 1. ASP木马概述 ASP…...

SpringBoot 架构助力夕阳红公寓管理系统可持续发展战略

摘 要 如今社会上各行各业&#xff0c;都在用属于自己专用的软件来进行工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。互联网的发展&#xff0c;离不开一些新的技术&#xff0c;而新技术的产生往往是为了解决现有问题而产生的。针对于夕阳红公…...

TCP、HTTP、RPC

一、TCP (Transmission Control Protocol) 定义 TCP&#xff08;传输控制协议&#xff09;是一种面向连接、可靠传输的传输层协议&#xff0c;用于在计算机网络中提供端到端的数据通信服务。它是互联网协议套件的一部分&#xff0c;与IP&#xff08;互联网协议&#xff09;一…...

《C++ 中 RNN 及其变体梯度问题的深度剖析与解决之道》

在当今人工智能蓬勃发展的浪潮中&#xff0c;递归神经网络&#xff08;RNN&#xff09;及其变体长短期记忆网络&#xff08;LSTM&#xff09;和门控循环单元&#xff08;GRU&#xff09;在处理序列数据方面展现出了强大的潜力。然而&#xff0c;当我们在 C中着手实现这些网络时…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

前端开发者常用网站

Can I use网站&#xff1a;一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use&#xff1a;Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站&#xff1a;MDN JavaScript权威网站&#xff1a;JavaScript | MDN...

小智AI+MCP

什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析&#xff1a;AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github&#xff1a;https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...