C++:继承用法详解~

         在学完C++的类和对象,并掌握了类的核心语法与基本用法之后;我们就得去学习一下继承的语法,与继承的用法。简单概括一下,继承是C++中一种代码复用的手段,它允许我们,对已有的类,增添新的成员函数或变量,产生的新类,叫做子类。而本期博客,就是讲解继承的用法,如果这篇博客对你学习或工作上有帮助,还请多多点赞+收藏,万分感谢~ 

一、继承的基础概念(核心)

1、继承的用法展示

        在我们现实生活中,每一所学校都拥有自己的教务系统,而教务系统中,存储着学生,老师以及学校一些其它的信息。在用代码实现教务系统的时候,我们需要用一个学生类储存学生的信息,我们又需要一个老师类储存老师的信息。类的定义如下:
        这里只是简单的表示了一下:一个学生类,一个老师类,分别需要哪些属性和方法。可是我们从代码中发现,两者存在一定的代码重复,显得过于冗余。而C++中,因为继承机制的存在,我们可以对这两个类进行,下面的处理:

class Person
{
protected:string name = "周天津"; // 名字int old = 58; // 年龄string ID = "111081200631313111"; // 身份证号string tel = "11188888888"; // 手机
};class teacher : public Person
{
public:void stude(){cout << "老师" << name << endl;cout << "年龄" << old << endl;cout << "ID" << ID << endl;cout << "电话" << tel << endl;cout << "职工" << work << endl;}
private:string work = "数学老师";
};

        运行一下,看看效果: 

2、继承的定义与使用

  1. 继承是C++中一种代码复用的手段,它允许我们,对已有的类,增添新的成员函数或变量,产生的新类,叫做子类。继承是一种层次结构的复用,体现了代码从简单到复杂;通过继承手段,我们可以使类得到复用。每种书的用语习惯不同,被复用的类可以称为父类也可以是基类,在此基础上产生的新类,叫做子类或派生类。
  2. 继承的使用格式:class    子类名    :    继承方式    父类名

3、继承方式

  • 在C++中,继承方式存有3种:public继承、protected继承、private继承(这里复用三个访问权限修饰符),那不同方式的继承有什么作用呢?——不同方式的继承,影响着父类中不同,访问权限的成员继承之后,在子类当中的访问权限
    1. 无论是什么继承,父类的私有成员,在子类中都是不可见的。
    2. 父类的其余成员,继承方式与访问权限限定符,选择其中权限最小的;如:保护继承,父类的公有成员变保护,保护成员还是保护。
    3. 当父类的成员,不想在类外之间访问,而想在子类中访问的时候,可以将父类的成员实现为保护成员。可见保护成员与私有成员的不同就在此处。
    4. 继承方式不显示写的时候,struct定义的类,默认是公有基础,class定义的类,默认是私有继承。
    5. 现实中,最常用的继承方式是公有继承~

三种继承方式总结:

父类成员public继承projected继承private继承
publicpublicprojectedprivate
protectedprotectedprojectedprivate
private 不可见不可见

不可见

4、隐藏规则

  • 在继承体系中⽗类和⼦类都有独⽴的作⽤域。
  • 父类与子类,若存在成员变量名相同,则构成成员变量隐藏;
  • 父类与子类,若存在成员函数名相同,则构成成员函数隐藏;
  • 注意隐藏,只需要函数名相同即可。
  • 所谓隐藏,就是子类指针或引用,去调用构成隐藏关系的成员变量或成员函数的时候,默认的是子类中的成员函数,或成员变量~
  • 若想要调用父类中成员函数,或成员变量,则可以通过指明类型。

5.子类与父类对象间的赋值兼容转换

  • 子类的实例化对象、或其指针、引用,可以赋值给父类的实例化对象、或其指针、引用。这里是一种切片的效果,所以不涉及类型转换问题,在赋值的时候,不会产生临时对象。
  • 父类的实例化对象不能赋值给子类的实例化对象,但父类的指针或引用,可通过强制类型转换,赋值给子类的指针或引用,但前提是确保安全性。

6、子类的默认成员函数

  • 子类(派生类),作为一个类,同样会存在六种默认成员函数(C++11,会存在八种);而需要我们去重点学习的有:构造函数、析构函数、拷贝构造函数、赋值运算符重载,我们需要通过以下两个方面去学习这四种函数。
    1. 编译器默认生成的,其行为是什么?
    2. 如果编译器默认生成的,不能满足我们呢的需要,我们又该如何显示实现呢?
    3. 我将通过代码+注释,将这四种成员函数的行为,以及如何显示实现,展示出来。还请区分侧重点,自行通过IDE进行逐一验证,或详细内容还请跳转至类与对象篇。
    4. 我这里只会总结,比较重要的默认成员函数中的知识点~
    5. 详细内容还请跳转至类与对象篇。

i、构造函数
  • 总结:(初始化列表,定义变量的顺序:先父类后子类,其中又符合先声明的先定义)
  • 子类默认构造函数的行为:
    1. 调用父类的默认构造函数(无参构造函数,有参但全缺省构造函数,编译器自动生成的构造函数都属于默认构造函数);若父类无默认构造函数,则编译器报错。
    2. 内置类型编译器的行为是未知的。
    3. 自定义类型,编译器调用自定义类型的默认构造函数,若无默认构造函数,则编译器报错。
    4. 可见,编译器对子类中父类的行为,和,对对象的行为基本类似。
  • 显示写子类构造函数:
    1. 父类的初始化,必须在初始化列表中进行;若不显示写父类的初始化,则调用父类的默认构造函数,若父类无默认构造函数,则编译器报错。内置类型编译器的行为是未知的。
    2. 显示调用父类构造函数:父类名(参数)
    3. 自定义类型和内置类型的初始化,和在普通类中,无区别。
class Person // 基类
{
public:Person() = default; // 强制编译器生成 -> 默认构造函数Person(const char* name, size_t age, const char* Addr) //普通构造函数:_name(name), _age(age), _Addr(Addr) {}protected:string _name = "庄梦涵"; // 名字size_t _age = 17;  // 年龄string _Addr = "河南龙门镇庄村"; // 籍贯
};class student : public Person // 派生类
{
public:student() = default; // 强制编译器生成 -> 默认构造函数student(const char* name, size_t age, const char* Addr, const char* grade) // 普通构造函数:Person(name, age, Addr), _grade(grade){}void test(){cout << "_name:" << _name << endl;cout << "_age:" << _age << endl;cout << "_Addr:" << _Addr << endl;cout << "grade:" << _grade << endl;}
protected:string _grade = "大二"; 
};int main()
{student zmh;zmh.test();cout << endl;student cmy("常梦圆",17,"神垕","大四");cmy.test();return 0;
}

ii、析构函数
  • 总结:(析构函数,析构变量的顺序要求:先子类后父类,其中又符合后声明的先析构)
  • 子类默认析构函数的行为:
    1. 对于子类的,内置类型编译器的行为是未知的。
    2. 对于子类的,自定义类型,编译器会调用它的析构函数。
    3. 将子类的成员变量都析构之后,再自动调用父类的析构函数。
  • 显示写子类析构函数:
    1. 同普通的自定义类型一样,无论我们是否显示调用其析构函数,编译器都会在其销毁之前自动调用析构函数。
    2. 所以,我们写子类的析构函数的时候,只需要负责子类新增,内置类型的成员变量指向资源的清理就行。至于自定义类型和父类,编译器会自动为我们清理。而这一目的,也是为了保证,先析构子类后析构父类。
    3. 虽然编译器会自动为我们调用父类的析构函数,可若我们偏要显示调用的时候,也不是不可以——但必须要指明类域,否则编译器会报错。
    4. 父类和子类的析构函数,构成隐藏。至于为什么,因为C++的重写,需要函数名相同。

iii、拷贝构造函数
  • 总结:(默认生成的拷贝构造函数是一种浅拷贝;若需要资源的申请与释放则需要自己实现)
  • 子类默认拷贝构造函数的行为:
    1. 需要知道的是,拷贝构造函数是构造函数的重载形式之一;
    2. 对父类的处理:首先会去调用父类的拷贝构造函数,
    3. 对自定义类型的处理:会去调用自定义类型的拷贝构造函数。
    4. 对内置类型的处理:编译器直接进行值拷贝~
  • 显示写子类拷贝构造函数:
    1. 拷贝构造函数的函数名为类名相同;第一个参数必须是类名的引用(通常是const 引用,也不能有缺省值);并且没有返回类型(void也 没有);拷贝构造函数可以有其他参数(必须有缺省值),但这不是常见做法。
    2. 对父类的处理:在初始化列表中,显示调用父类的拷贝构造函数。
    3. 对自定义类型的处理:在初始化列表中,显示调用自定义类型的拷贝构造函数。
    4. 对内置类型的处理:完成正确的初始化与赋值,可以是在构造函数的函数体中,也可以是初始化列表。

iiii、赋值运算符重载

        总结:赋值运算符重载函数的行为,无论是编译器自动生成的,还是人为实现的,都与拷贝构造函数相似。只不过前者是对已有对象进行赋值,后者是对正在创建的对象的初始化。

        注:父类与子类的赋值运算符重载函数,构成隐藏关系,通过子类、子类指针或引用,显示调用父类的赋值运算符时,还请标明类域。

二、继承进阶(细节)

1、实现一个不能被继承的类

  1. ⽗类的构造函数私有,⼦类的构成必须调⽤⽗类的构造函数,但是⽗类的构成函数私有化以后,⼦类看不⻅就不能调⽤了,那么⼦类就⽆法实例化出对象。
  2. C++11新增了⼀个final关键字,final修改⽗类,⼦类就不能继承了。

2、继承与友元

        父类的友元函数,不能被子类继承;若想要该函数同时能访问父类和子类,则需要都进行友元声明。

3、继承与静态成员

        父类被子类继承后,父类的静态成员在子类中,与父类共用,下面则是一个静态成员count,记录当前已实例化对象的个数。

class WK
{
public:WK(){cout << "当前已创建ZMH/WK类个数:" << ++count << endl;}~WK(){cout << "当前已创建ZMH/WK类个数:" << --count << endl;}
protected:static int count;
};class ZMH :public WK {};int WK::count = 0;int main()
{WK d1,d2,d3;{ZMH d4, d5, d6;}WK d7;return 0;
}

 

4、单继承与多继承

i、继承模型
  • 单继承:⼀个⼦类只有⼀个直接⽗类时称这个继承关系为单继承。
  • 多继承:⼀个⼦类有两个或以上直接⽗类时称这个继承关系为多继承,多继承对象在内存中的模型是,先继承的⽗类在前⾯,后⾯继承的⽗类在后⾯,⼦类成员在放到最后⾯。
  • 菱形继承:菱形继承是多继承的⼀种特殊情况菱形继承有数据冗余和⼆义性的问题。⽀持多继承就⼀定会有菱形继承,所以实践中我们也是不建议设计出菱形继承这样的模型的。

5、继承与组合的比较

  • public继承是⼀种is-a的关系。也就是说每个⼦类对象都是⼀个⽗类对象。
  • 组合是⼀种has-a的关系。假设B组合了A,每个B对象中都有⼀个A对象。
  • 继承允许你根据⽗类的实现来定义⼦类的实现。这种通过⽣成⼦类的复⽤通常被称为⽩箱复⽤(white-box reuse)。术语“⽩箱”是相对可视性⽽⾔:在继承⽅式中,⽗类的内部细节对⼦类可⻅继承⼀定程度破坏了⽗类的封装,⽗类的改变,对⼦类有很⼤的影响。⼦类和⽗类间的依赖关系很强,耦合度⾼。
  • 对象组合是类继承之外的另⼀种复⽤选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接⼝。这种复⽤⻛格被称为⿊箱复⽤(black-box reuse),因为对象的内部细节是不可⻅的。对象只以“⿊箱”的形式出现。 组合类之间没有很强的依赖关系,耦合度低。优先使⽤对象组合有助于你保持每个类被封装。
  • 总结:在实现一个类中,若继承和组合的复用手段都可以使用,则更推荐使用组合。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

opencv实战项目十六:kmeans图像颜色聚类:

文章目录 前言K-means介绍效果 前言 在数字化时代&#xff0c;图像处理技术已成为计算机视觉领域的重要组成部分。其中&#xff0c;图像颜色聚类作为一项关键技术在众多应用场景中发挥着重要作用&#xff0c;如图像分割、物体识别、色彩调整等。K-means算法作为一种经典的聚类…

【云游戏】点量云流赋能大型游戏新体验

点量小刘发现近期国产化大型3A游戏《黑神话&#xff1a;悟空》的发售&#xff0c;可谓是赢得了一波好评。从场景内容来说深厚的文化底蕴支撑和高质量精美的特效及画面制作令人眼前一亮&#xff0c;作为备受瞩目的一款游戏&#xff0c;从技术层面来说&#xff0c;该游戏也离不开…

【DSP+FPGA】基于DSP+FPGA XC7K325T与TMS320C6678的通用信号处理平台

DSP FPGA 协同处理架构板载 1 个TMS320C6678 多核DSP处理节点板载 1 片 XC7K325T FPGA处理节点板载 1 个FMC 接口板载4路SFP光纤接口FPGA 与 DSP 之间采用高速Rapid IO互联 基于FPGA与DSP协同处理架构的通用高性能实时信号处理平台&#xff0c;该平台采用1片TI的KeyStone系列多…

制造企业如何启用BI工具,并构建自助式BI业务模式?

在制造业的数字化转型浪潮中&#xff0c;商业智能BI工具正逐渐成为推动企业增长的“加速引擎”。随着数据量的爆炸性增长&#xff0c;如何高效地分析和利用数据&#xff0c;已成为制造业提升竞争力的关键。本文将基于BI工具在制造业中的优势&#xff0c;深入探讨一种创新的BI分…

[Meachines] [Insane] Bankrobber XSS-MDOG+SQLI+XSRF+Local-RCE+Bankv2转账模拟应用缓冲区溢出

信息收集 IP AddressOpening Ports10.10.10.154TCP:80&#xff0c;443&#xff0c;445&#xff0c;3306 $ nmap -p- 10.10.10.154 --min-rate 1000 -sC -sV -Pn PORT STATE SERVICE VERSION 80/tcp open http …

jenkins安装k8s插件发布服务

1、安装k8s插件 登录 Jenkins&#xff0c;系统管理→ 插件管理 → 搜索 kubernetes&#xff0c;选择第二个 Kubernetes&#xff0c;点击 安装&#xff0c;安装完成后重启 Jenkins 。 2、对接k8s集群、申请k8s凭据 因为 Jenkins 服务器在 kubernetes 集群之外&#xff0c;所以…

JVM垃圾回收算法:标记-清除算法 、复制算法、 标记-整理算法、 分代收集算法

文章目录 引言I 标记回收算法(Mark-Sweep)算法不足II 复制算法(Copying)III 标记整理算法(Mark-Compact)IV 分代收集(以上三种算法的集合体)内存划分新生代算法:Minor GC老年代算法V 查看JVM堆分配引言 垃圾回收(Garbage Collection,GC) Java支持内存动态分配、…

机器学习/数据分析案例---糖尿病预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 这是一篇数据分析/机器学习很好的入门案例&#xff0c;对糖尿病的影响进行预测和分析通过随机森林预测&#xff0c;平均准确率和召回率都不错不足&#x…

Pytorch实现多层LSTM模型,并增加emdedding、Dropout、权重共享等优化

简述 本文是 Pytorch封装简单RNN模型&#xff0c;进行中文训练及文本预测 一文的延申&#xff0c;主要做以下改动&#xff1a; 1.将nn.RNN替换为nn.LSTM&#xff0c;并设置多层LSTM&#xff1a; 既然使用pytorch了&#xff0c;自然不需要手动实现多层&#xff0c;注意nn.RNN…

Threejs之OrbitControls轨道控制器

本文目录 前言一、Orbitcontrols&#xff08;轨道控制器&#xff09;1.1 基础使用1.2 代码演示 二、效果展示 前言 Orbitcontrols&#xff08;轨道控制器&#xff09;可以使得相机围绕目标进行轨道运动。 一、Orbitcontrols&#xff08;轨道控制器&#xff09; 1.1 基础使用 C…

【Python 千题 —— 基础篇】身份证隐藏的信息

Python 千题持续更新中 …… 脑图地址 👉:⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐ 题目描述 题目描述 在一个用户信息管理系统中,你需要处理和验证用户提供的身份证号。编写一个程序来从用户信息字符串中提取和验证身份证号,并提供相应的处理方式…

图论----最小生成树讲解与相关题解

目前已更新系列 当前--图论----最小生成树讲解与相关题解 滑动窗口系列算法总结与题解一 算法系列----并查集总结于相关题解 图论---dfs系列 差分与前缀和总结与对应题解&#xff08;之前笔试真的很爱考&#xff09; 数论---质数判断、质因子分解、质数筛&#xff08;埃氏…

在 Cilium CNI 集群上运行 vCluster 虚拟集群

上周在 KubeCon China 2024 大会上&#xff0c;我和社区伙伴们作为志愿者在 Cilium 项目展台与用户交流。有位用户询问 Cilium 是否能与 vCluster 集成&#xff0c;当时未能给出明确答复&#xff0c;特地回来后进行了测试。 答案是&#xff1a;在最新的 vCluster v0.20 中容器…

【Python篇】Python 类和对象:详细讲解(上篇)

文章目录 Python 类和对象&#xff1a;详细讲解1. 什么是类&#xff08;Class&#xff09;类的定义 2. 什么是对象&#xff08;Object&#xff09;创建对象 3. 属性和方法属性&#xff08;Attributes&#xff09;方法&#xff08;Methods&#xff09;在类中定义属性和方法使用对…

重生奇迹MU 小清新职业智弓MM

游戏中有一种令人迷醉的职业——智弓MM&#xff0c;她们以高超的射箭技能闻名于世。本文将为您介绍这个悠闲的小清新职业&#xff0c;在游戏中的特点以及如何成为一名出色的智弓MM。跟随我们一起探索这个奇妙而神秘的职业吧&#xff01; 悠闲的游戏节奏是游戏的初衷之一&#…

52 mysql 启动过程中常见的相关报错信息

前言 我们这里主要是看一下 service mysql start, service mysql stop 的过程中的一些常见的错误问题 这些 也是之前经常碰到, 但是 每次都是 去搜索, 尝试 1, 2, 3, 4 去解决问题 但是 从来未曾思考过 这个问题到底是 怎么造成的 The server quit without updating PID fil…

【设计模式】创建型模式——抽象工厂模式

抽象工厂模式 1. 模式定义2. 模式结构3. 实现3.1 实现抽象产品接口3.2 定义具体产品3.3 定义抽象工厂接口3.4 定义具体工厂3.5 客户端代码 4. 模式分析4.1 抽象工厂模式退化为工厂方法模式4.2 工厂方法模式退化为简单工厂模式 5. 模式特点5.1 优点5.2 缺点 6. 适用场景6.1 需要…

用3点结构的s1顺序标定2点结构的s2顺序

在行列可自由变换的条件下&#xff0c;3点结构有6个 (A,B)---6*30*2---(0,1)(1,0) 让A分别是3a1&#xff0c;2&#xff0c;…&#xff0c;6&#xff0c;让B全是0。当收敛误差为7e-4&#xff0c;收敛199次取迭代次数平均值&#xff0c;得到 迭代 搜索难度 1 13913.2 1 2 …

客服系统简易版

整体架构解读 客服端和商城端都通过websocket连接到客服系统, 并定期维持心跳当客户接入客服系统时, 先根据策略选择在线客服, 然后再发送消息给客服 websocket实现 用netty实现websocket协议, 增加心跳处理的handler, 详见chat-server模块 客服路由规则 暂时仅支持轮询的…

视频结构化从入门到精通——视频结构化主要技术介绍

视频结构化主要技术 1 视频接入 “视频接入”是视频结构化管道的起点&#xff08;SRC Point&#xff09;视频接入是视频结构化处理的第一步&#xff0c;它涉及将视频数据从各种采集源获取到系统中进行进一步处理。视频接入的质量和稳定性对后续的数据处理、分析和应用至关重要…