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

C++之继承详解

一.继承基础知识

继承定义:

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保
原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象
程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继
承是类设计层次的复用

 

例如:

class Person
{
public://
private:int _age;string cellphone;string name;
};
class Student :public Person
{
public://
private:int _student_id;
};
class Teacher :public Person
{
public://
private:int _teacher_id;
};

你仔细观察上面代码,会发现再学生和老师类上我们后面都跟了:public Person说明这两个类是继承Person的内容

现在我们再来学习下格式:

定义格式:

关于派生类和基类大家看下都能理解,现在我们重点来讲解下什么是继承方式

继承方式简单理解就是子类对于父类中的成员可以进行的操作,如下:

类成员/继承方式public继承protected继承private继承
基类的public成员派生类的public成员派生类的protected
成员
派生类的private
成员
基类的protected
成员
派生类的protected
成员
派生类的protected
成员
派生类的private
成员
基类的private成
在派生类中不可见在派生类中不可见在派生类中不可 见

总结:
1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私
有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面
都不能去访问它

2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在
派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的
3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他
成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected
> private。

4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过
最好显示的写出继承方式。
5. 在实际运用中一般使用都是public继承,几乎

很少使用protetced/private继承,也不提倡
使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里
面使用,实际中扩展维护性不强

 

二.基类和派生类对象赋值转换

派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片
或者切割
。寓意把派生类中父类那部分切来赋值过去。
基类对象不能赋值给派生类对象。
基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类
的指针是指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用RTTI(RunTime Type Information)的dynamic_cast 来进行识别后进行安全转换

 

如下:

class Person
{
public:
private:int age;string name;
};
class Student :public Person
{
public:
private:string _id;
};
class Teacher :public Person
{
public:
private:string _id;
};
int main()
{Student s;//子类可以切片给父类对象//派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用//派生类对象 可以赋值给 基类的对象Person p1 = s;//派生类对象 可以赋值给 基类的指针Person* p2 = &s;//派生类对象 可以赋值给 基类的引用Person& p3 = s;//但注意;基类不能赋值给派生类Person p4;//Teacher t1 = p4;return 0;
}

但基类一定不能传给派生类吗???

我们发现此时是可以赋值给子类了,这是特殊情况的处理,而且转换时可能会出现越界的情况

知识扩展:

我们知道在不同类型赋值时会存在类型转换,那么你知道下面这行代码出错的原因吗???

看到报错原因,你以为是int不能传给double,还是要强制类型转换

实际上这是因为引用赋值时,会产生一个临时变量,该零时变量具备常性,所以我们必须用const修饰,防止权限扩大

这样就可以通过了

总结:如果要通过引用来复制拷贝,我们一定要观察是否会出现零时变量,从而确定是否需要用const修饰

三.继承中的作用域

1. 在继承体系中基类和派生类都有独立的作用域
2. 子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,
也叫重定义
。(在子类成员函数中,可以使用 基类::基类成员 显示访问
3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏
4. 注意在实际中在继承体系里面最好不要定义同名的成员

 

如果你仔细观察过上一个代码,你会发现在Student和Teacher中都出现了_id这个成员变量,这就是隐藏

下面在看这道题:

class A
{
public:void func(){//}
private:int _a;
};
class B :public A
{
public:void func(int a=10){//}
private:int _a;
};

请问B中的func函数和A中的func函数是什么关系???

a.   无关系                         b.  重定义(隐藏)                           c.重载

答案是:b

c重载是指在相同作用域中两个同名函数由于参数的不同所构成的,而且只有返回类型不同是不构成重载的

而且这两个类属于不同作用域,看定义:
成员函数的隐藏,只需要函数名相同就构成隐藏

那么我们如何访问父类成员变量呢???

如下:

四.派生类的默认成员函数(重点)

class Person
{
public://构造函数;Person(const string& s):_name(s){}//拷贝构造Person(const Person& p):_name(p._name){}//复值重载Person& operator=(const Person& p){if (&p != this){this->_name = p._name;return *this;}else{exit(-1);}}//析构函数~Person(){//析构}
protected:string _name;
};
class Student :public Person
{
public://构造函数;//派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认//的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用Student(const Student& s):_age(s._age),Person(s){}Student(const int& age,const string& name):_age(age),Person(name){}//注意的是:构造函数实际给成员变量赋值时,是先给父类赋值的,即使我们初始化列表中子类在前!!!//拷贝构造//派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化Student(const Student& s):_age(s._age),Person(s)//注意这里是切割{}//赋值重载//派生类的operator = 必须要调用基类的operator = 完成基类的复制Student& operator=(const Student& s){if(this!=&s){_age = s._age;Person::operator=(s);//注意这里operator函数和父类是隐藏的关系}else{exit(-1);}}//析构函数://派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能//保证派生类对象先清理派生类成员再清理基类成员的顺序//析构先析构子类,构造先构造父类~Student(){//析构子类//父类会自动调用的,不用写}
protected:int _age;
};

五.友元和静态成员

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员
 

此时我们写成友元就可以访问了

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子
类,都只有一个static成员实例
即我们可以通过父类和子类访问同一个静态成员

六.复杂的菱形继承及菱形虚拟继承

单继承:一个子类只有一个直接父类时称这个继承关系为单继承
 

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
 

此时就会出现一种特殊的继承;菱形继承:菱形继承是多继承的一种特殊情况

菱形继承的问题:可以看出菱形继承有数据冗余和二义性的问题。在d的对象中A成员会有两份

此时我们通过限定符去访问A中的成员对象就会出现B和C都可以访问,而且访问的是不同的两个成员,此时就会出现二义性和冗杂
 

此时,C++引入了虚继承的概念。

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在B和C的继承A时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地方去使用。
 

class Person
{
public:
protected:string _name; // 姓名
};
class Student : virtual public Person
{
protected:int _num; //学号
};
class Teacher : virtual public Person
{
protected:int _id; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修课程
};

如图,虚继承只需要在:后面写上一个virtual即可,还要注意的是,不同的父类要通过,分隔开

接下来我们深入底层来看看虚继承是如何解决问题的。

菱形继承例子:

这就是一个典型的菱形继承关系

最后,感谢大家的支持!!!

相关文章:

C++之继承详解

一.继承基础知识 继承定义: 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保 持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象 程序设…...

C#装箱和拆箱

一,装箱 装箱是指将值类型转化为引用类型。 代码如下: 装箱的内部过程 当值类型需要被装箱为引用类型时,CLR(Common Language Runtime)会为值类型分配内存,在堆上创建一个新的对象。值类型的数据会被复…...

企业用大模型如何更具「效价比」?百度智能云发布5款大模型新品

服务8万企业用户,累计帮助用户精调1.3万个大模型,帮助用户开发出16万个大模型应用,自2023年12月以来百度智能云千帆大模型平台API日调用量环比增长97%...从一年前国内大模型平台的“开路先锋”到如今的大模型“超级工厂”,百度智能…...

linux 外部GPIO Watchdog驱动适配

前言 文章描述, 利用外部gpio看门狗芯片驱动芯片的复位功能。 芯片:RK3568 平台: Linux ubuntu.lan 4.19.232 #27 SMP Sat Sep 23 13:43:49 CST 2023 aarch64 aarch64 aarch64 GNU/Linux 硬件接线图示 看门狗芯片采用GPIO喂狗,W…...

活动回顾 | 走进华为向深问路,交流数智办公新体验

3月20日下午,“企业数智办公之走进华为”交流活动在华为上海研究所成功举办。此次活动由上海恒驰信息系统有限公司主办,华为云计算技术有限公司和上海利唐信息科技有限公司协办,旨在通过对企业数字差旅和HR数智化解决方案的交流,探…...

【Java】Oracle发布Java22最新版本

甲骨文(ORACLE)已经于2023年3月19日正式发布了最新版本的JDK,版本号:22 根据官方声明,Java 22 (Oracle JDK 22) 在性能、稳定性和安全性方面进行了数千种改进,包括对Java 语言、其API 和性能,以…...

Vue reactive函数的使用

let searchForm reactive({}); let data reactive({ isAdmin: true, isshowAccount: true }); reactive 是什么? reactive 是 Vue 3 Composition API 中的一个函数,用于创建一个包含响应式数据的对象。在 Vue 2.x 中,我们通常使用 data 选项…...

unity自动引用生成

using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using UnityEditor; using UnityEngine; using UnityEngine.UI;/// <summary> /// 模板脚本生成 /// </summary> public class ScriptCreater : EditorW…...

【Linux系统】线程互斥与同步

目录 一.几个概念 二.线程互斥 1.定义并初始化锁 2.加锁 3.解锁 4.销毁锁 三.互斥锁的本质 1.xchg的原子性 2.加锁的过程 3.解锁的过程 四.可重入VS线程安全 五.死锁 1.死锁的概念 2.具体实例 3.死锁产生的四个必要条件 4.解决或避免死锁 六.线程同步 七.…...

武汉星起航引领跨境电商新潮流,深耕亚马逊打造全方位合作新模式

在全球化的浪潮下&#xff0c;跨境电商已成为连接各国市场的重要桥梁&#xff0c;为无数企业带来了前所未有的发展机遇。在这一领域&#xff0c;武汉星起航电子商务有限公司以其独特的战略眼光和实战经验&#xff0c;成为引领行业发展的佼佼者。公司自2017年起便深耕亚马逊平台…...

GateWay路由规则

Spring Cloud GateWay 帮我们内置了很多 Predicates功能&#xff0c;实现了各种路由匹配规 则&#xff08;通过 Header、请求参数等作为条件&#xff09;匹配到对应的路由 1 时间点后匹配 server:port: 8888 spring:application:name: gateway-servicecloud:nacos:discovery:…...

shell脚本基础改造

一、基础的shell脚本格式 #!/bin/bash 2 #3 #********************************************************************4 #Author: LJH5 #QQ: 2…...

静态综合实验

一&#xff0c;1.搭建拓扑结构并启动。 2.根据题意得该图需要14个网段&#xff0c;根据192.168.1.0/24划分子网段&#xff0c;如下&#xff1a; 划分完如图所示&#xff1a; 二、配置IP地址 R1路由器&#xff1a; 1.进入系统视图并改名. 2.接口配置IP地址&#xff1a…...

Spring Web MVC入门(6)

应用分层 在开发的过程中, 我们会发现, 程序的代码有时会很"杂乱", 如果后面的项目更大了, 那就会更加地杂乱无章(文件乱, 代码内容乱). 也基于此, 接下来让我们来学习一下应用分层. 也类似于公司的组织架构 公司初创阶段, 一个人身兼数职, 既做财务, 又做人事,还有…...

muduo异步日志

muduo异步日志实现 陈硕老师的muduo网络库的异步日志的实现&#xff0c;今晚有点晚了&#xff0c;我明晚再把这个异步日志抽出来&#xff0c;作为一个独立的日志库。 所在文件 AsyncLogging.cc AsyncLogging.h LogFile.h LogFile.cc CountDownLatch.h CountDownLatch.cc…...

在智慧能源的发展历程中,哪些技术的出现起到了关键性的作用?

智慧能源作为一种全新的能源发展理念&#xff0c;正逐渐成为能源领域的热门话题。在智慧能源的发展历程中&#xff0c;有许多技术的出现起到了关键性的作用&#xff0c;推动了智慧能源的快速发展。 一、物联网技术 物联网技术使得能源设备可以实现互联互通&#xff0c;通过传感…...

SQLiteC/C++接口详细介绍sqlite3_stmt类(十三)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十二&#xff09; 下一篇&#xff1a; 待续 51、sqlite3_stmt_scanstatus_reset sqlite3_stmt_scanstatus_reset 函数用于重置指定语句对象最近一次执行的 WHER…...

扫雷(蓝桥杯,acwing)

题目描述&#xff1a; 扫雷是一种计算机游戏&#xff0c;在 2020 世纪 80 年代开始流行&#xff0c;并且仍然包含在某些版本的 Microsoft Windows 操作系统中。 在这个问题中&#xff0c;你正在一个矩形网格上玩扫雷游戏。 最初网格内的所有单元格都呈未打开状态。 其中 M个…...

macOS 通过 MacPorts 正确安装 MySQL 同时解决无法连接问题

如果你通过 sudo port install 命令正常安装了 MySQL&#xff0c;再通过 sudo port load 命令启动了 MySQL Server&#xff0c;此刻却发现使用 Navicat 之类的 GUI 软件无法连接&#xff0c;始终返回无法连接到 127.0.0.1 服务器。这是一个小坑&#xff0c;因为他默认使用了 So…...

Semi-supervised Open-World Object Detection

Semi-supervised Open-World Object Detection 摘要1 介绍2.准备工作提出的SS-OWOD问题设置2.1 基础架构3 方法3.1整体架构摘要 传统的开放世界对象检测(OWOD)问题设置首先区分已知和未知类别,然后在后续任务中引入标签时逐步学习未知对象。然而,当前的OWOD公式在增量学习…...

深度解析AI Agent的工具调用机制:注册发现、动态选择与执行链路设计

深度解析AI Agent的工具调用机制:注册发现、动态选择与执行链路设计 关键词 AI Agent, 工具调用, 注册发现, 动态选择, 执行链路, LLM, 函数调用 摘要 随着大型语言模型(LLM)的快速发展,AI Agent作为一种能够自主完成复杂任务的智能体正日益受到关注。本文将深度解析AI A…...

手机端访问 Web 服务器

手机端访问 Web 服务器 从手机端访问 S7-1200 Web 服务器&#xff0c;需要将 S7-1200 CPU 连接 Internet 网络或者本地无线接入点相连的网络。本文档是将 S7-1200 CPU 用网线直接连接到无线设备上&#xff0c;并将手机的 WIFI 信号连接到由无线设备创建的无线网络中。无线设备…...

达梦数据库安全加固避坑指南:那些等保评测中容易忽略的配置细节(DM8实测)

达梦数据库安全加固实战&#xff1a;等保评测中的高阶配置陷阱与优化策略 在数据库安全领域&#xff0c;达梦数据库作为国产化替代的重要选择&#xff0c;其安全配置的严谨性直接关系到等保评测的成败。许多中高级运维人员虽然熟悉基础安全设置&#xff0c;却常常在等保测评的关…...

金融可视化组件实战指南:美国线图、均线图与K线图的应用解析

1. 金融可视化三剑客&#xff1a;美国线图、均线图与K线图入门 第一次接触金融图表时&#xff0c;我被满屏的红绿柱子弄得头晕眼花。直到一位老交易员告诉我&#xff1a;"这些图表就像股票的心电图&#xff0c;读懂它们就能听见市场的心跳。"今天我们就来拆解金融领域…...

有没有一款工具可以一键降低重复率和AI相似度?

毕业季论文查重、AI 检测双重高压&#xff1f;重复率居高不下、AI 痕迹太明显反复被打回&#xff1f;别再熬夜逐字改写&#xff01;PaperRed、毕业之家、豆包、DeepSeek、QuillBot 五大王牌工具&#xff0c;搭载语义重构 AI 痕迹消除双引擎&#xff0c;真正实现一键降低重复率…...

终极指南:5个简单步骤免费解锁Cursor Pro完整AI编程体验

终极指南&#xff1a;5个简单步骤免费解锁Cursor Pro完整AI编程体验 【免费下载链接】cursor-free-vip [Support 0.45]&#xff08;Multi Language 多语言&#xff09;自动注册 Cursor Ai &#xff0c;自动重置机器ID &#xff0c; 免费升级使用Pro 功能: Youve reached your t…...

Google 迎来「DeepSeek 时刻」:TurboQuant算法实现bit无损、×加速、×压缩、零预处理舅

从 UI 工程师到 AI 应用架构者 13 年前&#xff0c;我的工作是让按钮在 IE6 上对齐&#xff1b; 13 年后&#xff0c;我用 fetch-event-source 订阅大模型的“思维流”&#xff0c;用 OCR 解锁图片中的文字——前端&#xff0c;正在成为 AI 产品的第一道体验防线。 最近&#x…...

高效查询:C++二分查找在年龄统计中的应用实践

1. 为什么需要二分查找处理年龄统计&#xff1f; 最近在做一个学生管理系统时&#xff0c;遇到了一个很有意思的问题&#xff1a;系统里有10万名学生信息&#xff0c;需要频繁查询某个年龄段的起止位置。最开始我用的是最简单的线性查找&#xff0c;结果每次查询都要遍历整个数…...

3大创新技术:重构Android设备标识获取的新范式

3大创新技术&#xff1a;重构Android设备标识获取的新范式 【免费下载链接】Android_CN_OAID 安卓设备唯一标识解决方案&#xff0c;可替代移动安全联盟&#xff08;MSA&#xff09;统一 SDK 闭源方案。包括国内手机厂商的开放匿名标识&#xff08;OAID&#xff09;、海外手机平…...

BERT中文文本分割效果惊艳展示:学术论文讲义自动划分为‘引言-方法-结论’

BERT中文文本分割效果惊艳展示&#xff1a;学术论文讲义自动划分为引言-方法-结论 1. 效果惊艳开场&#xff1a;让杂乱文本秒变结构清晰 你有没有遇到过这样的情况&#xff1a;拿到一份长达几十页的学术讲座录音转写稿&#xff0c;密密麻麻的文字堆在一起&#xff0c;找不到开…...