C++继承和多态

目录

继承

继承的意义

访问限定符、继承方式

赋值兼容规则(切片)

子类的默认成员函数

多继承

继承is a和组合has a

多态

什么是多态

形成多态的条件

函数重载,隐藏,重写的区别

override和final

多态原理


继承

继承的意义

继承本质就是类之间代码的复用,通过子类继承父类的方式,让子类对象中具有父类对象的成员。

访问限定符、继承方式

通过访问限定符,可以限制子类可以继承哪些变量,不能继承哪些变量,在实际开发过程中通常使用公有public继承。父类中想要让子类继承的成员就用protected或public修饰,不想让子类看到就用private修饰。

赋值兼容规则(切片)

子类对象,指针,引用分别赋值给父类对象,指针,引用时,会遵循赋值兼容规则(切片)。即把子类对象中父类对象的可见范围给到父类对象、指针、引用

子类的默认成员函数

默认成员函数主要包括构造函数,拷贝构造,赋值运算符重载,析构函数。那么在子类中他们是如何调用的呢?(考虑到要初始化子类对象中的父类对象

子类的初始化包括对子类成员的初始化和对继承的父类成员的初始化

由于父类的默认成员函数在子类内是可见的,所以在初始化父类成员时,只需要调用父类的默认成员函数即可。子类成员再另当初始化。

例如,基类为Person,子类为Student的代码:

class Person
{
public:Person(string name,int age,string gender):_name(name),_age(age),_gender(gender){cout << "Person()" << endl;}Person(const Person& p){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person.operator=()" << endl;return *this;}~Person(){cout << "~Person()" << endl;}
protected:string _name;//姓名int _age;//年龄string _gender;//性别
};
class Student:public Person
{
private:string _id;//学号string _college;//所属学院
public:Student(string name, int age, string gender,string id,string college):Person(name,age,gender)//调用父类构造,_id(id),_college(college){//初始化子类成员cout << "Student()" << endl;}Student(const Student& s):Person(s)//调用父类拷贝构造{//拷贝子类成员cout << "Student(const Student& s)" << endl;}Student& operator=(const Student& s){Person::operator=(s);//调用父类的operator=cout << "Student.operator=()" << endl;//赋值子类成员return *this;}~Student(){//默认自动先调用子类析构,再调用父类析构cout << "~Student()" << endl;}
};
int main()
{Student s("cx", 20, "男", "2022112102601", "计算机与信息工程学院");//构造Student s2 = s;//拷贝构造Student s3("xxx", 18, "女", "2022112102728", "经济管理学院");//构造s3 = s2;//赋值return 0;
}

代码输出结果:

多继承

多继承:多继承就是一个类可以继承多个父类。

多继承会导致的问题:菱形继承,图示如下

为什么说菱形继承会有问题?

由于继承的本质是代码的复用,而菱形继承会导致A类对象在D类对象中存在两份,导致数据冗余和二义性。

如何解决:虚继承

虚继承就是多个类 在继承重复类时,都使用虚继承。这样在上图中D对象内就只会有一份A对象,消除了对象的冗余。

继承is a和组合has a

继承和组合本质都是代码的复用,使得一个对象存在于另一个对象之中。

继承:

class B
{
protected:int _b;
};
class A :public B
{
//A中可以直接使用父类的protected和public成员
protected:int _a;
};

组合:

class B
{
protected:int _b;
};
class A
{
protected:B _b;//B类对象作为成员,只能使用B类对象的public成员int _a;
};

由于组合只能使用另一个对象的公有成员,这使得组合而成的类之间耦合度更低,因此在组合和继承都可以达到目的时,组合方案更优。

多态

什么是多态

多态:多态就是一个接口多种实现,多种状态,是面向对象编程语言的一重要特征。当使用父类指针或引用接收子类对象指针或引用,并调用子类对象中重写的虚函数时,就会体现出多态性。即指向父类调父类,指向子类调子类

class Animal //基类
{
public:virtual void say()//虚函数{cout << "animal say " << endl;}
};
class Cat:public Animal  //子类,重写基类的虚函数
{
public:virtual void say(){cout << "cat say miao~miao~" << endl;}
};
class Dog :public Animal  //子类,重写基类的虚函数
{
public:virtual void say(){cout << "dog say wang~wang~" << endl;}
};
void func(Animal* n)//基类指针/引用接收
{n->say();//多态调用
}
int main()
{Animal a;Cat c ;Dog d;func(&a);func(&c);func(&d);return 0;
}

上面的代码基类为Animal,子类有Cat和Dog,当使用基类指针或引用接收对象的指针或引用时,指向哪个类调用哪个类的虚函数。

形成多态的条件

1.具有继承关系

2.虚函数重写

3.父类指针或引用调用虚函数

函数重载,隐藏,重写的区别

重载:同一作用域内,函数名相同,参数不同。

隐藏(重定义):子类函数和父类函数名字相同。父类函数就被隐藏了。

重写(覆盖):子类函数和父类函数名字相同,参数相同,返回类型相同,且父类函数是虚函数。

override和final

子类重写父类虚函数时,用override修饰子类重写的函数,用于检查是否成功重写(三同或者协变)。如果不构成重写在编译时就会报错。

用final修饰的类,不允许有子类继承

用final修饰的虚成员函数,在子类中不可被重写

多态原理

首先看一下这段代码

class A
{
public:void func(){;}
};
int main()
{A a;cout << sizeof(a) << endl;return 0;
}

因为类的成员函数存放在代码段,并不会在每个对象中单独存放一份,所以这里是空类,但是打印的是1,是因为要用至少一个字节来标识不同的对象。

class A
{
public:virtual void func(){;}
};
int main()
{A a;cout << sizeof(a) << endl;return 0;
}

这个类的大小是多少呢?

这又是为什么呢?为什么函数由普通函数变为虚函数,对象的大小就变了呢?

这是因为类中的每个虚函数地址要放到一个专门的位置,即虚函数表中。

对象中会多存放一个虚函数表指针,虚函数表中存放着一个类中所有的虚函数指针。

指针的大小在32位计算机上为4字节,64位计算机为8字节,所以类的大小变为8字节。

这和多态有什么关系呢?

子类继承父类时,会把父类对象中的虚函数表也继承下来。


重写虚函数前:

子类虚函数表中的虚函数地址和父类虚函数表中的虚函数地址是相同的。

重写之后:子类虚函数表中的虚函数地址会被重写的虚函数地址"覆盖"。

虚函数指针被覆盖后,此后在多态的条件下,基类指针指向父类对象时,编译器会在父类对象的虚函数表中查找虚函数,指向子类对象时,编译器会在子类对象的虚函数表中查找虚函数。进而体现出了指向谁,调用谁的多态性。

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

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

相关文章

Algorithms,最全的Python算法仓库!

学习编程、学习Python最好的方式就是练习&#xff0c;哪怕是新手&#xff0c;只要不断地敲代码输出&#xff0c;肯定会有神效。 Python的练手项目很多&#xff0c;特别是Github上&#xff0c;建议不管新手、老司机都去看看。 这里推荐给大家一个Gitthub上练习的项目&#xff…

[C++]——同步异步日志系统(5)

同步异步日志系统 一、日志消息格式化设计1.1 格式化子项类的定义和实现1.2 格式化类的定义和实现 二、日志落地类设计2.1 日志落地模块功能实现与测试2.2 日志落地模块功能功能扩展 一、日志消息格式化设计 日志格式化模块的作用&#xff1a;对日志消息进行格式化&#xff0c…

深度学习工具和资源推荐:全面指南

今天我们来聊聊深度学习的工具和资源。要学好深度学习&#xff0c;除了理论知识&#xff0c;还需要掌握一些强大的工具和找到好的资源。以下是我在学习过程中发现的一些非常有用的工具和资源&#xff0c;希望对你们有帮助。 目录 工具推荐 1. Python编程语言 2. TensorFlow…

接口测试返回参数的自动化对比!

引言 在现代软件开发过程中&#xff0c;接口测试是验证系统功能正确性和稳定性的核心环节。接口返回参数的对比不仅是确保接口功能实现的手段&#xff0c;也是测试过程中常见且重要的任务。为了提高对比的效率和准确性&#xff0c;我们可以通过自动化手段实现这一过程。本文将…

WGCLOUD登录页面支持输入验证码吗

支持的 v3.5.3版本开始&#xff0c;WGCLOUD支持在登录页面配置输入验证码&#xff0c;我们可以根据自己的场景需要&#xff0c;配置是否在登录页面显示验证码&#xff0c;如下说明 登录页面添加验证码说明 - WGCLOUD

[超级详细系列]ubuntu22.04配置深度学习环境(显卡驱动+CUDA+cuDNN+Pytorch)--[3]安装cuDNN与Pytorch

本次配置过程的三篇博文分享分别为为&#xff1a; [超级详细系列]ubuntu22.04配置深度学习环境(显卡驱动CUDAcuDNNPytorch)--[1]安装显卡驱动 [超级详细系列]ubuntu22.04配置深度学习环境(显卡驱动CUDAcuDNNPytorch)--[2]安装Anaconda与CUDA [超级详细系列]ubuntu22.04配置深…

Web学习day04

mybatis 目录 mybatis 文章目录 一、查询 1.1结果映射 1.2多条件查询 1.3模糊查询 二、XML 书写规范 三、动态SQL 四、配置文件 4.1settings标签 4.2mappers标签 4.3environments标签 五、案例 5.1数据表 5.2实现类 5.3mapper实现 5.4工具类实现 5.5XML动态…

Python应用 | 基于flask-restful+AntDesignVue实现的一套图书管理系统

本文将分享个人自主开发的一套图书管理系统&#xff0c;后端基于Python语言&#xff0c;采用flask-restful开发后端接口&#xff0c;前端采用VueAntDesignVue实现。对其他类似系统的实现&#xff0c;比如学生管理系统等也有一定的参考作用。有问题欢迎留言讨论~ 关注公众号&am…

记一下blender曲线阵列

先说一下如何正常使用这个 这一次我是用来贴瓷砖 随便创建一个mesh 然后添加一个阵列修改器&#xff0c;然后再给他添加一个curve修改器&#xff0c;使用constant offset去偏移他 这里有个小细节 我第一次创建的curve 我选取之后&#xff0c;死活无法沿着曲线阵列&#xff…

.快速幂.

按位与&#xff08;Bitwise AND&#xff09;是一种二进制运算&#xff0c;它逐位对两个数的二进制表示进行运算。对于每一位&#xff0c;只有两个相应的位都为1时&#xff0c;结果位才为1&#xff1b;否则&#xff0c;结果位为0。如&#xff1a;十进制9 & 5转化为二进制&am…

ActiveMQ-CVE-2023-46604

Apache ActiveMQ OpenWire 协议反序列化命令执行漏洞 OpenWire协议在ActiveMQ中被用于多语言客户端与服务端通信。在Apache ActvieMQ5.18.2版本以及以前&#xff0c;OpenWire协议通信过程中存在一处反序列化漏洞&#xff0c;该漏洞可以允许具有网络访问权限的远程攻击者通过操作…

opencv 中如何通过欧式距离估算实际距离(厘米)

1&#xff1a;这个方法个人测试觉得是正确的&#xff0c;误差较小&#xff0c;目前满足我当前的需求&#xff0c;如果方法不对&#xff0c;请大家评论&#xff0c;完善。 2&#xff1a;确保拍摄的参照物是垂直的&#xff0c;如果不垂直&#xff0c;就会有误差&#xff0c;不垂…

低代码商城构建专家:Mall-Cook

Mall-Cook&#xff1a;用Mall-Cook&#xff0c;让电商创新触手可及- 精选真开源&#xff0c;释放新价值。 概览 Mall-Cook是一个面向未来的商城低代码开发平台&#xff0c;它通过提供直观的可视化界面&#xff0c;让开发者和商家能够快速构建和部署跨平台的电商解决方案。这个…

微信小程序如何实现登陆和注册功能?

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

服务器提交记录有Merge branch消除

背景&#xff1a;在共同开发分支release上&#xff0c;你提交了commit&#xff0c;push到服务器上时&#xff0c;发现有人先比你push了&#xff0c;所以你得先pull&#xff0c; 后再push&#xff0c;然而pull后自动产生了一个Merge branch的一个commit&#xff0c;这个commit本…

递归解决换零钱问题--回顾总结之递归的表达能力

前面为了保持叙述的流畅, 没有做太多的引申, 把总结推迟到了后面. 补上一些总结, 以防止出现 “下面呢? 下面没有了” 的尴尬. 方向性问题 虽然题目在一开始就暗示了这一点, 但首先, 我们还是要问, 它能用递归解决吗? 有点怀疑精神是好的, 既要低头走路, 更要抬头看路, 以防…

JDK14新特征最全详解

JDK 14一共发行了16个JEP(JDK Enhancement Proposals&#xff0c;JDK 增强提案)&#xff0c;筛选出JDK 14新特性。 - 343: 打包工具 (Incubator) - 345: G1的NUMA内存分配优化 - 349: JFR事件流 - 352: 非原子性的字节缓冲区映射 - 358: 友好的空指针异常 - 359: Records…

【JavaScript】解决 JavaScript 语言报错:Uncaught TypeError: XYZ is not iterable

文章目录 一、背景介绍常见场景 二、报错信息解析三、常见原因分析1. 对非数组类型使用 for...of 循环2. 对非可迭代对象使用扩展运算符3. 在 Promise.all 中传递非可迭代对象4. 使用解构赋值时&#xff0c;右侧值非可迭代 四、解决方案与预防措施1. 确保使用可迭代对象2. 使用…

各种Attention|即插即用|适用于YoloV5、V7、V8、V9、V10(一)

摘要 本文总结了各种注意力&#xff0c;即插即用&#xff0c;方便大家将注意力加到自己的论文中。 SE import torch from torch import nn class SEAttention(nn.Module): """ SENet&#xff08;Squeeze-and-Excitation Networks&#xff09;中的注意力…

C++进阶(while循环——函数应用)

知识点代码框架总结 输入n组数据 &#xff0c;对n组数据里面的每一组进行处理&#xff08;输出、求和 、运算、其他&#xff09; int n;//几组数据cin >> n;//2while(n--){//对每组数据进行处理}看到下面的样例&#xff0c;肌肉型反映出上面的框架//2// 1 2 3// 4 5 6若…