当前位置: 首页 > 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中着手实现这些网络时…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...