[C++]:15.继承

继承

  • 一.继承:
    • 1.继承的概念和基本操作:
      • 1.概念:
      • 2.基本操作:
    • 2.继承格式和多种继承方法:
      • 1.基本继承格式:
      • 2.继承关系+访问限定符
    • 3.子类对象和父类对象之间的赋值:
      • 1.为什么存在赋值兼容转换?
      • 2.子类对象赋值给父类对象(赋值兼容转换):
        • 2-1:对象赋值:
        • 2-2:对象指针赋值:
        • 2-3:对象引用赋值:
      • 3.总结:
    • 4.继承中的作用域:
      • 1.问题:子类和父类可以有同名成员?
        • 1-1:同名成员:
        • 1-2:同名函数:
      • 2.问题:子类和父类成员函数不是重载关系?
      • 3.总结:
    • 5.子类的默认成员函数!
      • 1.构造函数:
      • 2.析构函数:
      • 3.拷贝:
      • 4.赋值:
    • 7.继承和友元+继承和静态:
      • 1.继承和友元:
      • 2.继承和静态:
    • 8.多继承:
      • 1.菱形继承:特殊的多继承
      • 2.1.菱形虚拟继承:
    • 9.继承的总结和反思:
      • 1.多继承
      • 2组合和继承:
      • 3.继承的作用:

一.继承:

1.继承的概念和基本操作:

1.概念:

继承就是一种类的复用,我们以前写的代码比较多的都是在主函数中使用各种函数这是函数的复用,在接触类和对象以后需要学习类的复用也就是继承。继承是面向对象的,这样的语法可以让程序员在原来的类的基础上继承产生一个新的的类,这个新的的类有被继承类的成员函数和成员变量。

2.基本操作:

两个类一个老师类,一个学生类,提取两个类中共有的内容去反向定义一个类person类让老师类和学生类都去继承人这个类实现类的复用:我们先去写一个关于学生的复用。

	class preson {public:preson(string name="xxxx", string six="xxx", int age=18):_name(name),_six(six),_age(age){}void information_person(){cout << "名字:" << _name << endl;cout << "性别:" << _six << endl;cout << "年龄:" << _age << endl;}protected:string _name;string _six;int _age;};class student : public preson {public:student(int score,int grade):_score(score),_grade(grade){}void information_student(){//1.被继承的成员变量可以直接使用:cout << "名字:" << _name << endl;cout << "性别:" << _six << endl;cout << "年龄:" << _age << endl;//2.间接使用:information_person();//3.学生部分:cout << "成绩:" << _score << endl;cout << "年级:" << _grade << endl;}protected:int _score;int _grade;};int main(){sfpy::student s1(88, 1);s1.information_student();return 0;}

在这里插入图片描述

观察代码和运行结果,我们发现被继承的这个类当前的成员变量和成员函数我们都可以去使用,这个地方没有办法去指定学生的person类中的成员内容?

2.继承格式和多种继承方法:

1.基本继承格式:

在这里插入图片描述

2.继承关系+访问限定符

1.继承方式:public继承 ,protected继承 , private继承。
2.访问方式:public访问 ,protected访问 , private访问。
4.继承方式+访问方式才可以确定子类对父类的成员的使用情况!
5.注意:
5-1:不去显示的去写继承方式,class来说默认private继承 , struct是公有继承。
5-2:建议:public继承方式 + 成员变量使用保护 + 成员方法使用公有。
*
总结:父类的 A 成员 和 子类的B继承组合在一起,对于子类来说对于子类来说这个父类的成员在子类中有着 A&&B中较小的一个情况。
*
public > protected > private;
保护就是因为继承才产生的,公有+保护 保护+公有 保护+保护 对于子类来说都可以去使用父类的成员!
在这里插入图片描述

3.子类对象和父类对象之间的赋值:

1.为什么存在赋值兼容转换?

不同类型之间在进行 赋值,大小比较,的时候都会产生临时变量。通过临时变量进行操作。下面这个地方通过a的值产生了一个float类型的临时变量然后临时变量和b进行比较在这个地方。

int main()
{int a = 10;float b = 20.5;if (a > b){cout << "a>b" << endl;}else{cout << "a<b" << endl;}return 0;
}

子类赋值个父类的过程中是不存在中间变量的?
回答:临时变量具有常性不能把具有const类型的数据赋值给person对象。
解决办法:特殊处理—>赋值兼容转换—>中间不产生临时变量,做了一个切片处理。

2.子类对象赋值给父类对象(赋值兼容转换):

子类的对象---->赋值给---->父类对象
子类的对象指针---->赋值给---->父类对象指针
子类的对象引用---->赋值给---->父类对象引用

int main()
{sfpy::student s1(88, 1);//1.切片赋值--->产生新的切片:sfpy::preson p1 = s1;//2.切片赋值sfpy::preson* p2 = &s1;//3.切片赋值sfpy::preson& p3 = s1;return 0;
}
2-1:对象赋值:

在这里插入图片描述

2-2:对象指针赋值:

在这里插入图片描述

2-3:对象引用赋值:

在这里插入图片描述

3.总结:

在这里插入图片描述

4.继承中的作用域:

1.问题:子类和父类可以有同名成员?

回答:子类和父类属于不同的作用域可以有同名成员!

1-1:同名成员:
class preson {public:preson(string name = "xxxx", string six = "xxx", int age = 18):_name(name), _six(six), _age(age){}void information(){cout << "名字:" << _name << endl;cout << "性别:" << _six << endl;cout << "年龄:" << _age << endl;}protected:string _name;string _six;int _age;};class student : public preson {public:student(string name ,int score, int grade):_name(name),_score(score), _grade(grade){}void information(){//1.被继承的成员变量可以直接使用:指定类域cout << "名字:" << preson::_name << endl;cout << "性别:" << _six << endl;cout << "年龄:" << _age << endl;cout << "名字:" << _name << endl;cout << "成绩:" << _score << endl;cout << "年级:" << _grade << endl;}protected:string _name;int _score;int _grade;};

在这里插入图片描述

1.成员变量的一个同名成员,子类优先访问自己的成员变量,如果在这样的情况下想要去访问父类的成员变量需要指定类域去进行访问。
2.父子类的同名成员变量,构成隐藏关系。

1-2:同名函数:
namespace sfpy {class preson {public:preson(string name="xxxx", string six="xxx", int age=18):_name(name),_six(six),_age(age){}void information(){cout << "名字:" << _name << endl;cout << "性别:" << _six << endl;cout << "年龄:" << _age << endl;}protected:string _name;string _six;int _age;};class student : public preson {public:student(int score,int grade):_score(score),_grade(grade){}void information(){//1.被继承的成员变量可以直接使用:cout << "名字:" << _name << endl;cout << "性别:" << _six << endl;cout << "年龄:" << _age << endl;2.间接使用:指定类域person::information();//3.学生部分:cout << "成绩:" << _score << endl;cout << "年级:" << _grade << endl;}protected:int _score;int _grade;};}

1.成员变量的一个同名成员,子类优先访问自己的成员变量,如果在这样的情况下想要去访问父类的成员函数需要指定类域去进行访问。
2.父子类的同名成员函数,构成隐藏关系,不需要考虑返回值和参数的情况!

2.问题:子类和父类成员函数不是重载关系?

回答:构成重载需要成员函数在同一作用域下!

3.总结:

1.在实际的情况当中不需要去定义同名的成员!
2.注意函数重载和隐藏关系的不同。

5.子类的默认成员函数!

子类和父类的这些默认成员函数进行分别调用的!
1.对子类做处理就去掉用子类
2.对父类做处理就去掉用父类

1.构造函数:

1.不去使用父类的默认构造通过显示的去调用父类的构造可以通过子类传参的方法对父类的成员进行初始化构造。
2.父类有默认构造函数那么如果我们不去显示的调用构造那么走默认构造(无参,全缺省,列表初始化)

	class preson {public:preson(string name = "xxxx", string six = "xxx", int age = 18):_name(name), _six(six), _age(age){}void information_person(){cout << "名字:" << _name << endl;cout << "性别:" << _six << endl;cout << "年龄:" << _age << endl;}protected:string _name;string _six;int _age;};class student : public preson {public:student(string name,string six, int age,int score, int grade):preson(name,six,age), _score(score), _grade(grade){}void information_student(){//1.被继承的成员函数可以直接使用:information_person();cout << "成绩:" << _score << endl;cout << "年级:" << _grade << endl;cout << endl;}protected:int _score;int _grade;};

在这里插入图片描述

2.析构函数:

在这里插入图片描述

为什么我们在子类的析构函数中显示的去掉用父类的析构函数会报错?
1.有父子关系的两个类的析构函数名称会被统一转化为distruct。
2.两个类的析构函数就构成了隐藏的关系。
3.同名称的函数需要指定类域。

在这里插入图片描述

我们如果去显示的去析构对象,先析构子的部分还是父的部分?
1.我们应该先析构子节点再去析构父节点。
2.因为如果存在先析构父节点那么如果子节点的析构操作需要父节点的数值怎么办?
3.为了保证先去调用子节点后调用父节点子类的析构函数不需要显示的去调用父类的析构函数。编译器会在调用完子类的析构然后自动的去调用父类的析构

3.拷贝:

1.编译器默认生成的 拷贝构造会去完成值拷贝。
2.对于当前的例子来说完成值拷贝是没有问题的。
3.显示的去调用父类的拷贝构造子类的初始化列表中去使用。
4.我们知道在一些情况下有可能发生浅拷贝的问题是需要进行显示调用。

class preson {
public:preson(string name = "xxxx", string six = "xxx", int age = 18):_name(name), _six(six), _age(age){}preson(const preson& p1){_name = p1._name;_six = p1._six;_age = p1._age;}void information_person(){cout << "名字:" << _name << endl;cout << "性别:" << _six << endl;cout << "年龄:" << _age << endl;}~preson(){cout << "~preson" << endl;}
protected:string _name;string _six;int _age;
};class student : public preson {
public:student(string name, string six, int age, int score, int grade):preson(name, six, age), _score(score), _grade(grade){}student(const student& s1):preson(s1),_score(s1._score),_grade(s1._grade){}void information_student(){//1.被继承的成员函数可以直接使用:information_person();cout << "成绩:" << _score << endl;cout << "年级:" << _grade << endl;cout << endl;}~student(){preson::~preson();cout << "~student" << endl;}
protected:int _score;int _grade;
};}

4.赋值:

class preson {
public:preson(string name = "xxxx", string six = "xxx", int age = 18):_name(name), _six(six), _age(age){}preson(const preson& p1){_name = p1._name;_six = p1._six;_age = p1._age;}void information_person(){cout << "名字:" << _name << endl;cout << "性别:" << _six << endl;cout << "年龄:" << _age << endl;}preson& operator=(const preson& p){//1.不能自己给自己进行赋值:if (this != &p){_name = p._name;_six = p._six;_age = p._age;}return *this;}~preson(){cout << "~preson" << endl;}
protected:string _name;string _six;int _age;
};class student : public preson {
public:student(string name, string six, int age, int score, int grade):preson(name, six, age), _score(score), _grade(grade){}student(const student& s1):preson(s1),_score(s1._score),_grade(s1._grade){}void information_student(){//1.被继承的成员函数可以直接使用:information_person();cout << "成绩:" << _score << endl;cout << "年级:" << _grade << endl;cout << endl;}student& operator=(const student& s){//1.不能自己给自己进行赋值:if (this != &s){//2.分开显示的调用:preson::operator=(s);_score = s._score;_grade = s._grade;}return *this;}~student(){preson::~preson();cout << "~student" << endl;}
protected:int _score;int _grade;
};}

在这里插入图片描述

7.继承和友元+继承和静态:

1.继承和友元:

1.友元关系不可以继承,子类的友元不能访问子类的私有和保护。
2.如果想要使用友元函数那么应该在自己的类域中去声明友元函数。

2.继承和静态:

1,父类定义了一个static成员那么无论有多少子类继承,产生了多少对象,都只有这一个static成员实例。

8.多继承:

1.单继承:一个子类只去直接继承一个父类。

class A {
public:A(int a):_a(a){cout << "A()" << endl;}
protected:int _a;
};class B : public A{
public:B(int a, int b):A(a),_b(b){cout << "B()" << endl;}
protected:int _b;
};class C : public B {
public:C(int a, int b,int c):B(a,b), _c(c){cout << "B()" << endl;}
protected:int _c;
};

2.多继承:一个子类直接继承多个父类。

class A {
public:A(int a):_a(a){cout << "A()" << endl;}
protected:int _a;
};class B{
public:B(int b):_b(b){cout << "B()" << endl;}
protected:int _b;
};class C : public B,public A {
public:C(int a, int b,int c):B(b),A(a), _c(c){cout << "B()" << endl;}
protected:int _c;
};

1.菱形继承:特殊的多继承

在这里插入图片描述

菱形继承存在两个问题:
1.数据冗余:存储了很多不需要的数据。
2.二意性:作为老师有一个名称,作为学生有一个名称。

class preson {
public:preson(string name):_name(name){}protected:string _name;
};class student : public preson{
public:student(string name , int id):preson(name),_student_id(id){}
protected:int _student_id;
};class Teacher : public preson {
public:Teacher(string name, int id):preson(name), _teacher_id(id){}
protected:int _teacher_id;
};class Assistan : public student,public Teacher {
public:Assistan(string name_1 , string name_2,int id_1 , int id_2 , int money):student(name_1,id_1),Teacher(name_2,id_2),_money(money){}
protected:int _money;
};

1.person有一个属性名称。
2.作为学生有学生编号和名称。
3.作为老师有老师编号和名称。
4.作为助理继承了老师和学生的两个身份同时可以有工资这个属性。
5.这么一看好像没有什么问题但是人的公有属性名称在内存中的存贮是什么样子的?
6.如果说presson类有非常多的数据名字,住址,性别,身份证号等等,我们需要存贮两份数据吗?

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

2.1.菱形虚拟继承:

class A {
public:A(int a = 0):_a(a){cout << "A()" << endl;}
protected:int _a;
};class B : virtual public A{
public:B(int a , int b):A(a),_b(b){cout << "B()" << endl;}
protected:int _b;
};class C : virtual public A{
public:C(int a, int c):A(a),_c(c){cout << "B()" << endl;}
protected:int _c;
};class D :  public B , public C{
public:D(int a,int b,int c,int d):B(a,b),C(a,c),_d(d){}
protected:int _d;
};

为什么有虚继承?
在语法上新增加了一个虚继承去解决数据冗余和二意性。
注意:虚拟继承可以解决菱形继承继数据冗余和二意性问题,只能在B和C中去使用虚拟继承就可以解决问题。从底层来看相同的数据只会去保存一份节省了空间。

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

在这里插入图片描述

9.继承的总结和反思:

1.多继承

1.多继承是C++的缺陷,有了多继承就有菱形继承,不得不新增语法解决问题。

2组合和继承:

1.我们应该优先去使用组合而不是继承。
黑箱:组合
1.我们使用组合对象之间关系不太一个类被维护不会影响到另一个类。
2.为什么称为黑箱呢?
3.使用一个对象我们只需要去使用对象的接口我们不需要关心对象中内容只需要去使用相关的接口。对象里面的内容我们是看不见的!
4.组合之间没有非常强的依赖关系,耦合度底。

白箱:继承
1.对于子类来说父类就是一个白箱,父类中的内容我们大部分都可以访问到。操>作父类内容比较麻烦可能产生问题,
2.改变父类会影响子类,子类和父类的依赖关系是非常强的。
3.代码的耦合度是非常高的。

3.继承的作用:

在实际情况中可以使用组合就使用组合,组合的耦合度底,代码方便维护,对于继承来说合适使用继承的地方还是可以去使用继承,多态的前提条件也是需要有继承关系的。

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

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

相关文章

如果通过浏览器调试?

背景&#xff1a;博主是一个有丰富经验的后端开发人员&#xff0c;在前端开发中感觉总是有种力不从心的感觉&#xff0c;因为没有后端debug调试的清晰感。 解决办法&#xff1a;掌握chorm浏览器调试技巧。 F12&#xff0c; F5 打上断点之后&#xff0c;这不就是梦寐之中的调试…

vulhub中spring的CVE-2022-22947漏洞复现

Spring Cloud Gateway是Spring中的一个API网关。其3.1.0及3.0.6版本&#xff08;包含&#xff09;以前存在一处SpEL表达式注入漏洞&#xff0c;当攻击者可以访问Actuator API的情况下&#xff0c;将可以利用该漏洞执行任意命令。 参考链接&#xff1a; https://tanzu.vmware.c…

C语言-2

自定义类型 基本认识 /*引入&#xff1a;学生&#xff1a;姓名&#xff0c;学号&#xff0c;年龄&#xff0c;成绩请为学生们专门定制一个类型&#xff08;创造一个类型&#xff09;结构体格式&#xff1a;struct 标识符 // 标识符即自定义类型的名称{成员; // 自己设置…

【Qt5小项目】接金币小游戏

代码量在250行左右&#xff0c; 需要源码的可以私信我。

CCReportAdv的一个配置技巧

关于CCReportAdv CCReportAdv是我们推出的基于经典WinCC/TIA WinCC Prof.的一款报表控件。它支持导入Excel模板&#xff0c;可以灵活生成美观的数据报表。 配置示例 CCReportAdv功能非常强大。通过简单的配置就可以生成客户需要的报表。以下面这款报表为例&#xff0c;参见下面…

Multi ElasticSearch Head插件基本操作

Multi ElasticSearch Head插件安装好之后我们可以进行一些基本的操作。 1、复合查询 因为ES提供了一些Restful风格的接口&#xff0c;可以让任何语言去调用&#xff0c;因此我们可以将之前的请求地址粘贴到Multi ElasticSearch Head插件里面&#xff0c;选择GET请求方式&#x…

软件测试学习笔记-测试用例的编写

7中测试分类 按照阶段可划分单元测试、集成测试、系统测试、验收测试。代码可见度划分黑盒测试、灰盒测试、白盒测试 单元测试&#xff1a;针对源代码的测试 集成测试&#xff1a;针对接口进行测试 系统测试&#xff1a;针对功能和非功能的测试 验收测试&#xff1a;公测、内测…

Apache POI与easyExcel:Excel文件导入导出的技术深度分析

在处理Excel文件时&#xff0c;Java开发者经常会面临多种选择&#xff0c;其中Apache POI和easyExcel是两个非常受欢迎的选择。这两个库都提供了强大的Excel文件处理功能&#xff0c;但在性能、内存使用、API设计以及扩展性方面有所不同。本文将深入分析Apache POI和easyExcel在…

Git 实战场景过程(工作总结篇)

目录 前言1. Git远程仓库建立分支&#xff0c;本地未显示1.1 问题所示1.2 知识补充 2. Git暂存内容切换分支2.1 问题所示2.2 知识补充 3. Git放弃修改数据3.1 问题所示3.2 知识补充 4. git merge合并查看差异 前言 主要总结工作中的疑惑点&#xff0c;如果你也有相应的场景&am…

【Linux网络编程一】网络基础1(网络框架)

【Linux网络编程一】网络基础1&#xff08;网络框架&#xff09; 一.什么是协议1.通信问题2.协议本质3.网络协议标准 二.协议分层1.为什么协议要分层2.如何具体的分层 三.操作系统OS与网络协议栈的关系1.核心点&#xff1a;网络通信贯穿协议栈 四.局域网中通信的基本原理1.封装…

20.HarmonyOS App(JAVA)表格布局Layout使用方法

ability_main.xml&#xff0c;实现计算器键盘按钮 <?xml version"1.0" encoding"utf-8"?> <TableLayoutxmlns:ohos"http://schemas.huawei.com/res/ohos"ohos:height"match_parent"ohos:width"match_parent"oho…

【Midjourney】新手指南:命令

1./ask 向Midjourney提问&#xff0c;不过问题和回答都是英文的&#xff0c;例如&#xff1a; 2./blend 将两张图片合并为一张 ​ 3./describe 上传一张图片&#xff0c;Midjourney会生成四组该图片相关的关键词&#xff0c;可以使用这些关键词再生成图片。 ​ 4./turbo …

数据结构中的时间复杂度和空间复杂度基础

目录 数据结构 数据结构中的基本名词 数据 数据对象 数据元素 数据项 数据类型 数据对象、数据元素和数据项之间的关系 数据结构及分类 逻辑结构 物理结构 算法 算法的特点 算法设计上的要求 算法效率的衡量 时间复杂度 大O渐进表示法 最坏情况和平均情况 常…

大模型增量预训练新技巧:解决灾难性遗忘

大家好&#xff0c;目前不少开源模型在通用领域具有不错的效果&#xff0c;但由于缺乏领域数据&#xff0c;往往在一些垂直领域中表现不理想&#xff0c;这时就需要增量预训练和微调等方法来提高模型的领域能力。 但在领域数据增量预训练或微调时&#xff0c;很容易出现灾难性…

【开源】基于JAVA+Vue+SpringBoot的河南软件客服系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统管理人员2.2 业务操作人员 三、系统展示四、核心代码4.1 查询客户4.2 新增客户跟进情况4.3 查询客户历史4.4 新增服务派单4.5 新增客户服务费 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的河…

css新手教程

css新手教程 课程&#xff1a;14、盒子模型及边框使用_哔哩哔哩_bilibili 一.什么是CSS 1.什么是CSS Cascading Style Sheet 层叠样式表。 CSS&#xff1a;表现&#xff08;美化网页&#xff09; 字体&#xff0c;颜色&#xff0c;边距&#xff0c;高度&#xff0c;宽度&am…

Node.js-1

Node.js 简介 定义&#xff1a;Node.js 是一个跨平台 JavaScript 运行环境&#xff0c;使开发者可以搭建服务器端的 JavaScript 应用程序 为什么 Node.js 能执行 JS 代码&#xff1a; Chrome 浏览器能执行 JS 代码&#xff0c;依靠的是内核中的 V8引擎&#xff08;即&#x…

【Iot】什么是串口?什么是串口通信?串口通信(串口通讯)原理,常见的串口通信方式有哪些?

串口通信原理 1. 串口2. 串口通信4. 波特率与比特率5. 帧格式3. 串口通讯的通讯协议3.1. RS2323.2. RS485 总结 1. 串口 串行接口简称串口&#xff0c;也称串行通信接口或串行通讯接口&#xff08;通常指COM接口&#xff09;&#xff0c;是采用串行通信方式的扩展接口。 串口可…

python二维高斯热力图绘制简单的思路代码

import numpy as np import matplotlib.pyplot as plt from scipy.ndimage import gaussian_filter import cv2# 生成一个示例图像 image_size 100 image np.zeros((image_size, image_size))# 在图像中心创建一个高亮区域 center_x, center_y image_size // 2, image_size …

[工具探索]Safari 和 Google Chrome 浏览器内核差异

最近有些Vue3的项目&#xff0c;使用了safari进行测试环境搞开发&#xff0c;发现页面存在不同程序的页面乱码情况&#xff0c;反而google浏览器没问题&#xff0c;下面我们就对比下他们之间的差异点&#xff1a; 日常开发google chrome占多数&#xff1b;现在主流浏览器 Goog…