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

C++学习第十二天(继承)

1、继承的概念以及定义

继承的概念

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

class Person
{
public:void Print(){cout << "name:" << _name << endl;}
protected:string _name = "peter";//姓名int _age = 18; //年龄
};//继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了
//student和teacher复用了Person的成员。
class Student : public Person
{
protected:int _studentid;
};class Teacher : public Person
{
protected:int _workid;
};int main()
{Student s;Teacher t;s.Print();t.Print();return 0;
}

继承定义

定义的格式

class Student : public Person
{    //派生类  继承方式  基类
public:int _stuid;int _major;
}

继承关系和访问限定符

继承方式public继承protected继承private继承
访问限定符public访问protected访问private访问

继承基类成员访问方式的变化

类成员/继承方式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继承,很少使用protected或者是private继承
class Person
{
public:void Print(){cout << _name << endl;}
protected:string _name = "father";
private:int _age;
};
//class Student : public Person
//class Student : protected Person
class Student : private Person
{
public:void he(){Print();}
protected:int  _stu;
};

 2、基类和派生类对象赋值转换

  • 派生类对象可以赋值给 基类的对象/基类的指针/基类的引用。我们可以称这个过程为切片或者切割
  • 基类对象反之不能赋值给派生类对象
  • 基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象才是安全的。这里基类如果是多态类型,可以使用RTTI和dynamic_cast来进行识别后进行安全转换

class Person
{
protected:string _name;string _sex;int _age;
};class Student : public Person
{
public:int _No;
};void Test()
{Student s1;//1.子类对象可以赋值给父类对象/指针/引用Person s2 = s1;Person* s3 = &s1;Person& s4 = s1;//2.基类对象不能赋值给派生类对象//s1 = s2//3.基类的指针可以通过强制类型转换赋值给派生类指针s3 = &s1;Student* ps1 = (Student*)s3;ps1->_No = 10;s3 = &s2; Student* ps2 = (Student*)s3;//这种可能会出现越界访问ps2->_No = 10;
}

 3、继承中的作用域

  1. 在继承体系中基类个派生类都有独立的作用域
  2. 子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫做隐藏,也叫做重定义
  3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏
  4. 注意在实际中的基础体系中最好不要定义同名的成员
class Person
{
protected:string _name = "haha";int _num = 11;
};class Student : public Person
{
public:void Print(){cout << _name << endl;cout << Person::_num << endl;cout << _num << endl;}
protected:int _num = 100;
};void Test()
{Student s1;s1.Print();
}int main()
{Test();return 0;
}
class A
{
public:void fun(){cout << "fun()" << endl;}
};class B : public A
{
public:void fun(int i){A::fun();cout << "fun(int i)" << i << endl;}
};void Test()
{B b;b.fun(10);
}int main()
{Test();return 0;
}

 4、派生类默认成员函数

在派生类中,成员函数是怎么生成的呢?

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类的构造函数的初始化列表阶段显示调用
  2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化
  3. 派生类的operator=必须要调用基类的operator=完成基类的复制
  4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员在清理基类成员的顺序
  5. 派生类对象初始化先调用基类构造在调用派生类构造
  6. 派生类对象析构清理先调用派生类析构再调用基类的析构
  7. 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同。那么编译器会对析构函数名进行特殊处理,处理成destructor(),所以父类析构函数不加virtual的情况下,子类析构函数和父类析构函数构成隐藏关系

这个构造与析构顺序可以用栈来记忆

class Person
{
public:Person(const char* name = " peter"):_name(name){cout << "Person()" << endl;}Person(const Person& p):_name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}~Person(){cout << "~Person()" << endl;}
protected:string _name;
};class Student : public Person
{
public:Student(const char* name, int num):Person(name), _num(num){cout << "Student()" << endl;}Student(const Student& s):Person(s),_num(s._num){cout << "Student(const Student& s)" << endl;}Student& operator=(const Student& s){cout << "Student& operator = (const Student& s)" << endl;if (this != &s){Person::operator=(s);_num = s._num;}return *this;}~Student(){cout << "~Student()" << endl;}
protected:int _num;
};void Test()
{Student s1("jack", 10);Student s2(s1);Student s3("rose", 17);s1 = s3;
}int main()
{Test();return 0;
}

 5、继承与友元

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

class Student;
class Person
{
public:friend void Display(const Person& p, const Student& s);
protected:string _name;
};class Student : public Person
{
protected:int _stuid;
};void Display(const Person& p, const Student& s)
{cout << p._name << endl;cout << s._stuid << endl;//无法访问
}void Test()
{Person p;Student s;Display(p, s);
}

 6、继承与静态成员

基类定义了static成员,则整个继承体系里面只有一个这样的成员,无论派生出多少个子类,都只有一个static成员实例

class Person
{
public:Person() { ++_count; }
protected:string _name;
public:static int _count;
};int Person::_count = 0;
class Student : public Person
{
protected:int _stuNum;
};class Graduate : public Student
{
protected:string _semi;
};void Test()
{Student s1;Student s2;Student s3;Graduate s4;cout << "人数:" << Person::_count << endl;Student::_count = 0;cout << "人数:" << Person::_count << endl;
}int main()
{Test();return 0;
}

 7、复杂的菱形继承和菱形虚拟继承

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

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

菱形继承:菱形继承是多继承的一个特殊情况

菱形继承存在的问题:具有数据冗余和二义性问题,比如在最下面的Assistant对象中Person成员会有两份

class Person
{
public:string _name;
};class Student : public Person
{
protected:int _num;
};class Teacher : public Person
{
protected:int _id;
};class Assistant : public Student, public Teacher
{
protected:string _majorcourse;
};void Test()
{Assistant a;//编译器会不知道访问哪个_namea._name = "peter";//只有指定访问哪个父类的成员可以解决歧义的问题a.Student::_name = "haha";a.Teacher::_name = "hehe";
}int main()
{Test();return 0;
}

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。在Student和Teacher的继承Person时使用虚拟继承,就可以解决问题了。并且,虚拟继承不要在其他地方使用

class Person
{
public: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; // 主修课程
};
void Test()
{Assistant a;a._name = "peter";
}

虚拟继承解决数据冗余和二义性问题的原理,我们用一下代码来帮助我们来学习

class A
{
public:int _a;
};
// class B : public A
class B : virtual public A
{
public:int _b;
};
// class C : public A
class C : virtual public A
{
public:int _c;
};
class D : public B, public C
{
public:int _d;
};
int main()
{D d;d.B::_a = 1;d.C::_a = 2;d._b = 3;d._c = 4;d._d = 5;return 0;
}

编译器是这样子处理的:D对象中将A放到了对象呢组成的最下面,这个A同时属于B和C,那么A同时属于B和C,问题来了:B和C是如何找到公共的A呢?这里是通过了B和C的两个指针,指 向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量 可以找到下面的A。

相关文章:

C++学习第十二天(继承)

1、继承的概念以及定义 继承的概念 继承机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行拓展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承呈现了面向对象程序设计的层次结构&#x…...

WPF DataGrid绑定后端 在AutoGeneratingColumn事件中改变列名

public void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e){var propertyDescriptor (PropertyDescriptor)e.PropertyDescriptor;if (propertyDescriptor.IsBrowsable){e.Column.Header propertyDescriptor.DisplayName;}else{e.Cancel true;}}实体类中…...

2024 CorelDraw最新图形设计软件 激活安装教程来了

2024年3月&#xff0c;备受瞩目的矢量制图及设计软件——CorelDRAW Graphics Suite 2024 正式面向全球发布。这一重大更新不仅是 CorelDRAW 在 36 年创意服务历史中的又一重要里程碑&#xff0c;同时也展现了其在设计软件领域不断创新和卓越性能的领导地位。 链接: https://pan…...

双网口扩展IO支持8DO输出

M320E以太网远程I/O数据采集模块是一款工业级、隔离设计、高可靠性、高稳定性和高精度数据采集模块&#xff0c;嵌入式32位高性能微处理器MCU&#xff0c;集成2路工业10/100M自适应以太网模块里面。提供多种I/O&#xff0c;支持标准Modbus TCP&#xff0c;可集成到SCADA、OPC服…...

【负载均衡在线OJ项目日记】编译与日志功能开发

目录 日志功能开发 常见的日志等级 日志功能代码 编译功能开发 创建子进程和程序替换 重定向 编译功能代码 日志功能开发 日志在软件开发和运维中起着至关重要的作用&#xff0c;目前我们不谈运维只谈软件开发&#xff1b;日志最大的作用就是用于故障排查和调试&#x…...

yaml配置文件的在深度学习中的简单应用

1 .创作灵感 小伙伴们再阅读深度学习模型的代码的时候&#xff0c;经常会遇到yaml格式的配置文件。用这个配置文件是因为我们在训练模型的时候会涉及很多的参数&#xff0c;如果这些参数东一个&#xff0c;西一个&#xff0c;我们调起来的时候就会很不方便&#xff0c;所以用y…...

spring boot 核心配置文件是什么?

Spring Boot 的核心配置文件主要是 application.properties 或 application.yml&#xff08;也称为 YAML 格式&#xff09;。这两个文件通常位于项目的 src/main/resources 目录下&#xff0c;用于配置 Spring Boot 应用程序的各种属性和设置。 application.properties&#xf…...

Python的奇妙之旅——回顾其历史

我们这个神奇的宇宙里&#xff0c;有一个名叫Python的小家伙&#xff0c;它不仅聪明&#xff0c;而且充满活力。它一路走来&#xff0c;从一个小小的编程语言成长为如今全球最受欢迎的编程语言之一。今天&#xff0c;我们就来回顾一下Python的历史&#xff0c;看看它如何从一个…...

Flink面试整理-Flink的性能优化策略

Apache Flink 的性能优化是一个多方面的任务,涉及硬件资源、算法选择、配置调整等多个层面。以下是一些常见的 Flink 性能优化策略: 1. 资源分配和管理 合理配置 TaskManager 和 JobManager:根据作业的需求和可用资源,合理分配内存和 CPU 给 TaskManager 和 JobManager。适…...

SpringBoot与SpringMVC的区别

SpringBoot与SpringMVC的区别是什么&#xff1f; SpringBoot和SpringMVC是Java开发中常用的两个框架&#xff0c;它们都是由Spring框架所提供的&#xff0c;但在功能和使用方式上有着一些区别。本文将分别介绍SpringBoot和SpringMVC的特点和区别。 一、SpringBoot的特点&#…...

漏洞挖掘之某厂商OAuth2.0认证缺陷

0x00 前言 文章中的项目地址统一修改为: a.test.com 保护厂商也保护自己 0x01 OAuth2.0 经常出现的地方 1&#xff1a;网站登录处 2&#xff1a;社交帐号绑定处 0x02 某厂商绑定微博请求包 0x02.1 请求包1&#xff1a; Request: GET https://www.a.test.com/users/auth/weibo?…...

电脑屏幕监控软件都有哪些 | 五大好用屏幕监控软件盘点

电脑屏幕监控软件在企业管理、家庭教育等方面发挥着越来越重要的作用。 这些软件通过实时监控电脑屏幕活动&#xff0c;为用户提供了强大的管理和监控功能。 本文将为您盘点五大好用的电脑屏幕监控软件&#xff0c;帮助您更好地了解并选择适合自己的软件。 电脑屏幕监控软件都…...

数据结构-线性表-链表-2.3-2

在带头节点的单链表L中&#xff0c;删除所有值为x的结点&#xff0c;并释放其空间&#xff0c;假设值为x的结点不唯一&#xff0c; 是编写算法实现上述操作。 双指针&#xff0c;用p从头至尾扫描单链表&#xff0c;pre指向*p结点的前驱&#xff0c;若p所指结点的值为x&#x…...

【自动化测试】使用MeterSphere进行接口测试

一、接口介绍二、接口测试的过程三、接口自动化测试执行自动化流程 四、接口之间的协议HTTP协议 五、 接口测试用例设计接口文档 六、使用MeterSphere创建接口测试创建接口定义设计接口测试用例 一、接口介绍 自动化测试按对象分为&#xff1a;单元测试、接口测试、UI测试等。…...

C语言 main( ) 函数的指针数组形参是怎么回事?

一、问题 在使⽤⼀些开发⼯具⽣成C语⾔⽂件时&#xff0c;主函数 mian( ) 中会有参数&#xff0c;这个参数到底是怎么回事⼉呢&#xff1f; 二、解答 mian( ) 称为主函数&#xff0c;是所有程序运⾏的⼊口。 mian( ) 函数是由系统调⽤的&#xff0c;当处于操作命令状态下&…...

汽车 - 什么是车轮抱死

车轮抱死分为两种情况&#xff0c;一种是车辆故障层面&#xff0c;另一种是驾驶过程中的物理现象。我们先来说最通俗的刹车车轮抱死吧。 刹车制动车轮抱死 车轮停止轴向转动就是抱死&#xff0c;有速度的情况下抱死车轮&#xff0c;如果车辆的惯性动能大于轮胎抓地力&#xff0…...

环保设备统一管理系统

在环保意识日益增强的今天&#xff0c;企业如何有效管理环保设备&#xff0c;确保其正常运行&#xff0c;减少环境污染&#xff0c;成为了一个重要议题。HiWoo Cloud平台以其独特的环保设备统一管理系统&#xff0c;为企业提供了一套完整的解决方案&#xff0c;帮助企业实现绿色…...

python 11Pandas数据可视化实验

实验目的&#xff1a; 学会使用Pandas操作数据集&#xff0c;并进行可视化。 数据集描述&#xff1a; 该数据集是CNKI中与“中药毒理反应”相关的文献信息&#xff0c;包含文章题目、作者、来源&#xff08;出版社&#xff09;、摘要、发表时间等信息。 实验要求&#xff1…...

【JUC】并发编程 AQS,ReentryLock,CyclicBarrier,CountDownLatch 原理总结

AQS AQS是什么&#xff1f;重写AQS就能实现锁的效果&#xff1f; AQS是一个抽象类&#xff0c;是一个并发包的基础组件&#xff0c;用来实现各种锁&#xff0c;同步组件的工具&#xff08;通过volatile cas进行实现&#xff09;。它包含了共享成员变量state、等待队列、条件…...

移动端底层事件(如左滑返回事件)在同一个路由下不同页面需要不同的处理要怎样才能做到统一处理?

目录 一、问题 二、解决方法 三、总结 tiips:如嫌繁琐&#xff0c;直接移步总结即可&#xff01; 一、问题 1.测试提了个bug:进入了一个模块A里面的子页面 a1,左滑后按照用户预期应该是返回到模块A,结果回到了app首页。 二、解决方法 1.一开始&#xff1a;啊&#xff0c;…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

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

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

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...