C++ 继承

目录

    • 继承
    • 基类和派生类对象赋值转换
    • 继承中的作用域
    • 派生类的默认成员函数
    • 静态成员、友元与继承
    • 菱形继承和菱形虚拟继承
    • 虚拟继承原理
    • 继承和组合
    • 习题练习

继承

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

定义格式
Person是父类,也称作基类。Student是子类,也称作派生类
在这里插入图片描述

继承基类成员
在这里插入图片描述
在这里插入图片描述

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它。
  2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
  3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
  4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式
  5. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强

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

不同类型的对象赋值时,相近类型可以隐式类型转换(产生临时变量)
int和int* 就是相近类型,int表示数据大小,int* 是地址,本质是一个编号
在这里插入图片描述

r引用的不是d,而是中间的临时变量,临时变量有常性,所以要加const

在这里插入图片描述
基类对象不能赋值给派生类对象。

继承中的作用域

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

派生类的默认成员函数

class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}
protected:string _name; // 姓名
};class Student : public Person
{
public:Student(const char* name, int id):_id(id), Person(name){cout << "Student(const char* name, int id)" << endl;}
protected:int _id;
}

要把父类当成一个完整的对象初始化,而不是单个成员初始化(否则会编译报错)。要初始化父类就要显示调用父类的构造函数,不显示调用也会自动调用父类的默认构造函数,自动调用时:父类如果没有默认构造就会报错。

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 id):_id(id)//, Person(name){cout << "Student(const char* name, int id)" << endl;}Student(const Student& s):Person(s), _id(s._id){cout << "Student(const Student& s)" << endl;}Student& operator=(const Student& s){if (&s != this){Person::operator=(s);_id = s._id;}cout << "Student& operator=(const Student& s)" << endl;return *this;}~Student(){//Person::~Person();cout << "~Student()" << endl;}protected:int _id;
};int main()
{Student s1("张三", 18);Student s2(s1);Student s3("李四", 19);s1 = s3;return 0;
}

在这里插入图片描述

由于多态的原因,析构函数统一会被处理成destructor
父子类的析构函数构成隐藏
为了保证析构安全,先子后父
父类析构函数不需要显示调用,子类析构函数结束时会自动调用父类析构,不要显示调用,不然会多次调用。
保证先子后父

在这里插入图片描述

如何实现一个不能被继承的类?
C++98 私有化父类的构造函数
C++11 新增final,修饰父类,直接不能被继承,如:class A final

静态成员、友元与继承

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

静态成员可以说继承的是使用权,静态成员不属于某个对象,存在静态区,属于整个类,突破类域就能访问。
如果静态成员在父类是私有,在子类中这个静态成员不可见

菱形继承和菱形虚拟继承

单继承:一个子类只有一个直接父类时称这个继承关系为单继承
在这里插入图片描述

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
在这里插入图片描述

菱形继承:菱形继承是多继承的一种特殊情况
尽量不要使用菱形继承!
在这里插入图片描述
菱形继承有数据冗余和二义性的问题。
在Assistant的对象中Person成员会有两份。

class Person
{
public:string _name; // 姓名int _age;int _tel;// ...
};
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;//a._name = "peter";// 需要显示指定访问哪个父类的成员可以解决二义性问题,// 但是数据冗余问题无法解决a.Student::_name = "小张";a.Teacher::_name = "老张";
}int main()
{Test();return 0;
}

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

class Student : virtual public Person
class Teacher : virtual public Person

在这里插入图片描述

	a.Student::_name = "小张";a.Teacher::_name = "老张";a._name = "张三";都是同一份

虚拟继承原理

先继承谁,谁就在前
在这里插入图片描述

在这里插入图片描述

B的指针可以访问b也要可以访问a,为了解决二义性付出了一些代价,用存的地址去表里找偏移量,偏移量在00 的下一个位置存是因为00的位置要存其他值,和多态有关,用自己的地址加上偏移量就取到a了

如果存的地址直接就是a的地址或者存的就是偏移量都是可以的,但引入多态之后情况会复杂,所以选择了这个方法.
为了解决数据冗余用了虚拟继承,但我们发现用了虚拟继承之后空间用的更多了,就像做生意,少存了一份a,当a越大,节省的空间就越多
如果D对象有很多,都只需要指向这个表会很方便

继承和组合

public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。
组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。

//继承
class A
{
public:void func(){}
protected:int _a;
};class B : public A
{
public:void f(){func();_a++;}
protected:int _b;
};// 组合
class C
{
public:void func(){}
protected:int _c;
};class D
{
public:void f(){_c.func();//_c._a++;}
protected:C _c;int _d;
};

组合类的公有可以使用,组合类的保护就不可以使用了
对象的内部细节是不可见的。对象只以“黑箱”的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使用对象组合有助于你保持每个类被封装。

在继承方式中,基类的内部细节对子类可见。继承一定程度破坏了基类的封装,基类的改变,对派生类有很大的影响。派生类和基类间的依赖关系很强,耦合度高。

继承用起来比组合方便,但还是尽量多用组合,因为组合的耦合度低,代码维护性好。

习题练习

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

【MySQL索引与优化篇】数据库优化及性能分析工具使用

数据库优化及性能分析工具使用 文章目录 数据库优化及性能分析工具使用1. 数据库服务器优化的步骤2. 查询系统性能参数3. 定位执行满的SQL&#xff1a;慢查询日志4. 查看SQL执行成本&#xff1a;show profile5. 分析查询工具&#xff1a;explain5.1 id5.2 type 6. explain进一步…

作为20年老程序员,我如何使用GPT4来帮我写代码

如果你还在用google寻找解决代码bug的方案&#xff0c;那你真的out了&#xff0c;试试gpt4, save my life. 不是小编危言耸听&#xff0c;最近用gpt4来写代码极大地提高了代码生产力和运行效率&#xff0c;今天特地跟大家分享一下。 https://www.promptspower.comhttps://www.…

第7讲:VBA中利用FIND的代码实现多值查找实例

《VBA代码解决方案》(10028096)这套教程是我最早推出的教程&#xff0c;目前已经是第三版修订了。这套教程定位于入门后的提高&#xff0c;在学习这套教程过程中&#xff0c;侧重点是要理解及掌握我的“积木编程”思想。要灵活运用教程中的实例像搭积木一样把自己喜欢的代码摆好…

Unity DOTS系列之Struct Change核心机制分析

最近DOTS发布了正式的版本, 我们来分享一下DOTS里面Struct Change机制&#xff0c;方便大家上手学习掌握Unity DOTS开发。 基于ArchType与Chunk的Entity管理机制 我们回顾以下ECS的内存管理核心机制,基于ArchTypeChunk的Entity管理模式。每个Entity不直接存放数据&#xff0c…

[Python]unittest-单元测试

目录 unittest的大致构成: Test Fixture Test Case-测试用例 Test Suite-测试套件 Test Runner 批量执行脚本 makeSuite() TestLoader discover() 用例的执行顺序 忽略用例执行 skip skipIf skipUnless 断言 HTML测试报告 错误截图 unittest是python中的单元测…

亚马逊云科技为奇点云打造全面、安全、可扩展的数据分析解决方案

刘莹奇点云联合创始人、COO&#xff1a;伴随云计算的发展&#xff0c;数据技术也在快速迭代&#xff0c;成为客户迈入DT时代、实现高质量发展的关键引擎。我们很高兴能和云计算领域的领跑者亚马逊云科技一同&#xff0c;不断为客户提供安全可靠的产品与专业的服务。 超过1500家…

【操作系统】考研真题攻克与重点知识点剖析 - 第 1 篇:操作系统概述

前言 本文基础知识部分来自于b站&#xff1a;分享笔记的好人儿的思维导图与王道考研课程&#xff0c;感谢大佬的开源精神&#xff0c;习题来自老师划的重点以及考研真题。此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析&#xff0c;本人技术…

面向制造企业的持续发展,2023数字化工单管理系统创新篇章-亿发

面向制造企业的持续发展&#xff0c;2023数字化工单管理系统开创新篇章-亿发 随着制造业的持续发展&#xff0c;运维工单管理日益成为关键环节&#xff0c;它设计客户管理、设备维护、服务商合作等多个业务领域&#xff0c;对运营效率和服务质量有着重要影响。然而&#xff0c…

【鸿蒙软件开发】ArkTS基础组件之TextTimer(文本显示计时)、TimePicker(时间选择)

文章目录 前言一、TextTimer1.1 子组件1.2 接口参数TextTimerController 1.3 属性1.4 事件1.5 示例代码 二、TimePicker2.1 子组件2.2 接口参数 2.3 属性2.4 事件TimePickerResult对象说明 2.5 示例代码 总结 前言 通过文本显示计时信息并控制其计时器状态的组件。 时间选择组…

什么是 CNN? 卷积神经网络? 怎么用 CNN 进行分类?(3)

参考视频&#xff1a;https://www.youtube.com/watch?vE5Z7FQp7AQQ&listPLuhqtP7jdD8CD6rOWy20INGM44kULvrHu 视频7&#xff1a;CNN 的全局架构 卷积层除了做卷积操作外&#xff0c;还要加上 bias &#xff0c;再经过非线性的函数&#xff0c;这么做的原因是 “scaled p…

前端环境的安装 Node npm yarn

一 node npm 1.下载NodeJS安装包 下载地址&#xff1a;Download | Node.js 2.开始安装 打开安装包后&#xff0c;一直Next即可。当然&#xff0c;建议还是修改一下安装位置&#xff0c;NodeJS默认安装位置为 C:\Program Files 3.验证是否安装成功 打开DOS命令界面&#…

深度学习之基于Pytorch卷积神经网络的图像分类系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介二、功能三、图像分类系统四. 总结 一项目简介 基于PyTorch卷积神经网络的图像分类系统是一种应用深度学习技术来实现图像分类任务的系统。本摘要将对该系统…