[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.hqwc.cn/news/451039.html

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

相关文章

SparkStreaming---入门

文章目录 1.SparkStreaming简介1.1 流处理和批处理1.2 实时和离线1.3 SparkStreaming是什么1.4 SparkStreaming架构图 2.背压机制3.DStream案例实操 1.SparkStreaming简介 1.1 流处理和批处理 流处理和批处理是两种不同的数据处理方式&#xff0c;它们在处理数据的方式和特点…

python基于django的公交线路查询系统mf383

1.个人信息的管理&#xff1a;对用户名&#xff0c;密码的增加、删除等 2.线路信息的管理&#xff1a;对线路的增加、修改、删除等 3.站点信息的管理&#xff1a;对站点的增加、修改、删除等 4.车次信息的管理&#xff1a;对车次的增加、修改、删除等 5.线路查询、站点查询 …

ping 不支持代理,命令行测试外网网址请使用 curl 测试,如何测试?

如果你想通过命令行测试外网网址的可达性&#xff0c;并且因为 ping 命令不支持通过代理服务器进行操作&#xff0c;你可以使用 curl 命令来测试。curl 是一个强大的工具&#xff0c;可以用来传输数据&#xff0c;它支持多种协议&#xff0c;包括 HTTP、HTTPS 等&#xff0c;而…

前端面试题:二叉树广度和深度遍历

试题&#xff1a;有如下树形数据结构&#xff0c;通过JavaScript对二叉树实现深度遍历和广度遍历 广度遍历&#xff1a; 通过JavaScript数组模拟栈的方式实现&#xff0c;首先节点入栈&#xff0c;然后从栈顶取出节点&#xff0c;放入数组&#xff0c;然后对取出的节点进行遍历…

深度学习驱动下的自然语言处理进展及其应用前景

文章目录 每日一句正能量前言技术进步应用场景挑战与前景自然语言处理技术当前面临的挑战未来的发展趋势和前景 伦理和社会影响实践经验后记 每日一句正能量 一个人若想拥有聪明才智&#xff0c;便需要不断地学习积累。 前言 自然语言处理&#xff08;NLP&#xff09;是一项正…

三角函数与反三角函数公式

三角函数基本关系 对角线乘积为1 顶点等于相邻两个顶点乘积 阴影三角形上两顶点的平方和等于下顶点的平方 常用于&#xff1a;极限(少)、不定积分(多) 诱导公式 常见 二倍角公式 作用&#xff1a;统一角度 半角公式(降幂公式) 和差公式 积化和差公式 和差化积公式 万能公式(救命…

PHP入门指南:起步篇

PHP入门指南&#xff1a;起步篇 PHP入门指南&#xff1a;起步篇什么是PHP&#xff1f;PHP 的优点PHP 开发环境搭建选择本地服务器软件包安装PHP环境配置Web服务器和PHP测试PHP安装 第一个PHP脚本PHP基础语法标记注释变量数据类型常量条件语句循环函数 PHP入门指南&#xff1a;起…

【Docker篇】Linux安装Docker、docker安装mysql、redis、rabbitmq

1.Linux安装docker 官方帮助文档&#xff1a;Install Docker Engine on CentOS | Docker Docs 1.1安装命令 # 1. 卸载之前的dockersudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate…

使用maven对springboot项目进行瘦身分离jar的多种处理方案

文章目录 前言一、方案一&#xff08;修改自带的spring-boot-maven-plugin插件&#xff09;二、方案二&#xff08;使用spring-boot-thin-maven-plugin插件&#xff09;总结 前言 springboot项目打包一般我们都使用它自带的spring-boot-maven-plugin插件&#xff0c;这个插件默…

Feature refinement 的阅读笔记

Pattern Recognition上一篇微表情识别的文章&#xff0c;记录一下其中的关键信息点。 摘要&#xff1a; This paper proposes a novel Feature Refinement(FR) with expression-specific feature learning and fusion for micro-expression recognition. 本文的贡献是&#x…

RCS系统之:地图编辑

一般每个供应商都有不同的需求&#xff0c;不同的需求都会是在不同的场景下产生的。而不同的场景都会需要构建不同的地图数据。 所有一个动态编辑的地图的能力都软件&#xff0c;是非常有必要的。基于这个想法&#xff0c;我们提供了一个可以实时&#xff0c;动态编辑地图的界面…

十大排序算法之堆排序

堆排序 在简单选择排序文章中&#xff0c;简单选择排序这个“铁憨憨”只顾着自己做比较&#xff0c;并没有将对比较结果进行保存&#xff0c;因此只能一遍遍地重复相同的比较操作&#xff0c;降低了效率。针对这样的操作&#xff0c;Robertw.Floyd 在1964年提出了简单选择排序…