c++(六)

c++(六)

  • 多态
    • 概念
    • 在c++中是如何实现多态
      • 静态多态(绑定)
      • 动态多态(绑定)
    • 动态多态的实现原理
    • 动态内存分配中遇到的问题
  • 重载、重定义、重写的区别
  • 抽象类
  • 接口类---抽象类
  • 空类对象的内存大小
  • explicit
  • final
    • 修饰类
    • 修饰成员函数

在这里插入图片描述

多态

概念

多种状态(一个事物的多种状态或形态)

<1>水在不同的温度下呈现的不同状态
<2>买票
学生票;
成人票;
老年票;
军人;

在c++中是如何实现多态

绑定:就是把函数调用语句与对应的代码块进行了绑定!。

静态多态(绑定)

编译的时候,就知道执行的是哪一个函数体
调用函数时,函数名是一样的,当我们传入不同参数的时候,执行的是不同的函数体(函数重载、运算符重载)

动态多态(绑定)

在运行的时候,才知道执行的是哪一个函数体

案例:如果要求两个子类的周长和面积之和,就得写两个函数来实现,传入不同的对象
在这里插入图片描述

在这里插入图片描述

#include <iostream>
using namespace std;
class Shape
{
public:Shape(int s = 0, int c = 0) :s(s), c(c){cout << "Shape构造" << endl;}~Shape(){cout << "Shape析构" << endl;}int getC(){cout << "周长:" << this->c << endl;return this->c;}int getS(){cout << "面积:" << this->s << endl;return this->s;}
private:
protected:int s;int c;
};
class Rect:public Shape
{
public:Rect(int a = 0, int b = 0) :a(a), b(b){cout << "Rect构造" << endl;}~Rect(){cout << "Rect析构" << endl;}int getC(){this->c = (this->a + this->b) * 2;return this->c;}int getS(){this->s = this->a * this->b;return this->s;}void show(){cout << "周长:" << this->c << ",面积:" << this->s << endl;}
private:
protected:int a;int b;
};
class Circle:public Shape
{
public:Circle(int r = 0) :r(r){cout << "Circle构造" << endl;}~Circle(){cout << "Circle析构" << endl;}int getC(){this->c = 2 * 3.14 * this->r;return this->c;}int getS(){this->s = 3.14 * this->r * this->r;return this->s;}void show(){cout << "周长:" << this->c << ",面积:" << this->s << endl;}
private:
protected:int r;
};
void Rcs(Rect & demo)
{cout << demo.getC()+ demo.getS()<< endl;
}
void Ccs(Circle& demo)
{cout << demo.getC() + demo.getS() << endl;
}
int main()
{//矩形对象Rect rect(2,3);Rcs(rect);//圆形对象Circle circle(3);Ccs(circle);}

解决:用父类统一管理子类
在这里插入图片描述
问题:通过父类的引用操作子类的对象时,并没有执行子类的函数,执行的是子类从父类继承过来的函数
在这里插入图片描述
解决:目的:执行子类重定义的函数,将父类对应的函数写成虚函数
虚函数的格式:

virtual 返回值类型 函数名(参数列表){}

未加victual之前,不能访问子类重定义函数的原因:
将子类对象强制赋值给父类的引用,父类的引用所访问的范围小,访问不到子类的函数
在这里插入图片描述

#include <iostream>
using namespace std;
class Shape
{
public:Shape(int s = 0, int c = 0) :s(s), c(c){cout << "Shape构造" << endl;}~Shape(){cout << "Shape析构" << endl;}virtual int getC(){cout << "周长:" << this->c << endl;return this->c;}virtual int getS(){cout << "面积:" << this->s << endl;return this->s;}
private:
protected:int s;int c;
};
class Rect:public Shape
{
public:Rect(int a = 0, int b = 0) :a(a), b(b){cout << "Rect构造" << endl;}~Rect(){cout << "Rect析构" << endl;}int getC(){this->c = (this->a + this->b) * 2;return this->c;}int getS(){this->s = this->a * this->b;return this->s;}void show(){cout << "周长:" << this->c << ",面积:" << this->s << endl;}
private:
protected:int a;int b;
};
class Circle:public Shape
{
public:Circle(int r = 0) :r(r){cout << "Circle构造" << endl;}~Circle(){cout << "Circle析构" << endl;}int getC(){this->c = 2 * 3.14 * this->r;return this->c;}int getS(){this->s = 3.14 * this->r * this->r;return this->s;}void show(){cout << "周长:" << this->c << ",面积:" << this->s << endl;}
private:
protected:int r;
};
void Scs(Shape & demo)
{cout << demo.getC()+ demo.getS()<< endl;
}
int main()
{//矩形对象Rect rect(2,3);Scs(rect);//圆形对象Circle circle(3);Scs(circle);}

在这里插入图片描述

动态多态的实现原理

有虚函数一定能实现动态多态吗?不一定

多态的实现:
<1>一个父类,有多个子类
<2>父类中有虚函数,子类重写父类的虚函数
<3>用父类对象的指针或者引用去操作子类的对象并调用虚函数的受,才会触发动态多态(决定性因素)

将父类的对应的函数写成虚函数,在子类中进行重写,通过父类对象的指针/引用去操作子类对象就可以调用到子类的函数了

指针所能访问的空间的大小:由指针指向的数据类型大小决定

int *p; //4字节
shape *p;// 8个字节

在这里插入图片描述
为什么添加virtual就可以访问子类的函数?

虚函数表:保存虚函数的地址(函数指针数组)

什么时候有虚函数表?

一个类中一旦有了虚函数,那么这个类中就有了一个虚函数表,保存这个类中所有虚函数的地址,如果这个类被子类继承了,子类中也会有一张虚函数表

父类的虚函数表和子类的虚函数表一样吗?

<1>如果子类不重写父类的虚函数,那么父类和子类的虚函数表是一样的
<2>如果子类重写了父类的虚函数,那么子类虚函数表中对应的就是子类重写之后的虚函数地址

在这里插入图片描述

  1. 父类有虚函数,那么被子类继承之后,子类中对应的函数也是虚函数!子类中对应函数的virtual关键字可加可不加!
  2. 父类中有函数是虚函数,如果子类有重定义的话,此时被称为重写(覆盖–就是子类中的函数把从父类中继承来的给覆盖了。子类中有且只有一个这样子的函数!!!)!!!!
  3. 重写就必须保证 子类中的函数首部与父类中函数的首部是一模一样的,首部指的是:函数类型 函数名(参数列表)。

动态内存分配中遇到的问题

问题:把new出来的子类对象,赋值给了父对象类型的指针,在整个操作过程中,都是通过父类的指针来操作,使用delete去释放空间的时候,只执行了父类的析构函数,并没有子类的析构函数,可能会造成内存泄漏的问题(在子类的构造函数去new空间了)
在这里插入图片描述

在这里插入图片描述

解决:目标:执行子类的析构函数
将父类的析构函数写成虚函数,子类的析构自然也是虚函数!

在这里插入图片描述

#include <iostream>
using namespace std;
class Shape
{
public:Shape(int s = 0, int c = 0) :s(s), c(c){cout << "Shape构造" << endl;}virtual ~Shape(){cout << "Shape析构" << endl;}virtual int getC(){cout << "周长:" << this->c << endl;return this->c;}virtual int getS(){cout << "面积:" << this->s << endl;return this->s;}
private:
protected:int s;int c;
};
class Rect :public Shape
{
public:Rect(int a = 0, int b = 0) :a(a), b(b){cout << "Rect构造" << endl;}~Rect(){cout << "Rect析构" << endl;}int getC(){this->c = (this->a + this->b) * 2;return this->c;}int getS(){this->s = this->a * this->b;return this->s;}void show(){cout << "周长:" << this->c << ",面积:" << this->s << endl;}
private:
protected:int a;int b;
};
class Circle :public Shape
{
public:Circle(int r = 0) :r(r){cout << "Circle构造" << endl;}~Circle(){cout << "Circle析构" << endl;}int getC(){this->c = 2 * 3.14 * this->r;return this->c;}int getS(){this->s = 3.14 * this->r * this->r;return this->s;}void show(){cout << "周长:" << this->c << ",面积:" << this->s << endl;}
private:
protected:int r;
};
void Scs(Shape* demo)
{cout << demo->getC() + demo->getS() << endl;
}
int main()
{Shape* p = new Circle(4);Scs(p);delete p;}

<1>在设计类的时候,为什么建议把析构函数写成虚函数
防止内存泄漏
<2>为什么不执行子类的析构函数就可能会存在内存泄漏的问题
在子类的构造函数去new空间了

重载、重定义、重写的区别

重载:同一个作用域内,函数功能相似,函数名相同、参数不同,与返回值无关的一组函数
重定义:在继承关系中,子类重定义父类的函数,函数名相同即可
重写(覆盖):在继承关系中,子类重写父类的虚函数
备注:函数首部必须一样
首部:返回值类型 函数名(形式参数列表)

抽象类

在设计类的时候,发现这个类确实需要这样子的一个操作函数,但是在父类中不知道该怎么实现,它的所有的子类都要实现这个函数,并且所有的子类实现这个函数的效果是不一样的,这种情况下,就可以把这个函数写成纯虚函数

virtual 返回值类型 函数名(形参列表) = 0;

在这里插入图片描述
注意:抽象类是不能创建对象的
在这里插入图片描述

作用:就是用来被继承的,在子类中去实现这个纯虚函数(每一个子类都要去实现这个纯虚函数)
如果子类没有实现这个纯虚函数,子类也变成了抽象类

#include <iostream>
using namespace std;
class Shape //抽象类
{
public:Shape(int s = 0, int c = 0) :s(s), c(c){cout << "Shape构造" << endl;}virtual ~Shape(){cout << "Shape析构" << endl;}virtual int getC() = 0;//纯虚函数virtual int getS() = 0;private:
protected:int s;int c;
};
class Rect :public Shape
{
public:Rect(int a = 0, int b = 0) :a(a), b(b){cout << "Rect构造" << endl;}~Rect(){cout << "Rect析构" << endl;}int getC(){this->c = (this->a + this->b) * 2;return this->c;}int getS(){this->s = this->a * this->b;return this->s;}void show(){cout << "周长:" << this->c << ",面积:" << this->s << endl;}
private:
protected:int a;int b;
};
class Circle :public Shape
{
public:Circle(int r = 0) :r(r){cout << "Circle构造" << endl;}~Circle(){cout << "Circle析构" << endl;}int getC(){this->c = 2 * 3.14 * this->r;return this->c;}int getS(){this->s = 3.14 * this->r * this->r;return this->s;}void show(){cout << "周长:" << this->c << ",面积:" << this->s << endl;}
private:
protected:int r;
};
void Scs(Shape* demo)
{cout << demo->getC() + demo->getS() << endl;
}
int main()
{Shape* p = new Circle(4);Scs(p);delete p;}

在这里插入图片描述

接口类—抽象类

接口类其实就是抽象类的应用
当抽象类不能实例化对象时,抽象类中的成员变量也就不能初始化,其构造函数也就不能被执行

接口类:类中只有成员函数,没有数据成员,并且成员函数必须是纯虚函数
作用:就是用来被继承的,描述一些能力、协议

#include <iostream>
using namespace std;
//接口类
class fly_land
{
public:virtual void fly() = 0;//纯虚函数virtual void land() = 0;
};
class Bird :public fly_land
{
public:void fly(){cout << "bird  fly ....." << endl;}void land(){cout << "bird land....." << endl;}
};
class Plane :public fly_land
{
public:void fly(){cout << "plane fly....." << endl;}void land(){cout << "plane land....." << endl;}
};
void dosomething(fly_land& demo)
{demo.fly();
}
int main()
{Bird bird;dosomething(bird);Plane plane;dosomething(plane);
}

在这里插入图片描述

空类对象的内存大小

默认构造函数、析构函数、默认拷贝构造函数、赋值运算符函数、取值运算符函数 const 修饰的取值运算符
空类占内存大小:1字节
在这里插入图片描述
在这里插入图片描述

explicit

作用:修饰构造函数的,对应的构造函数被称为 转换构造函数!!!!
意义:防止构造函数单参数的时候进行自动类型的转换

在这里插入图片描述

final

作用:修饰类和类中的成员函数

修饰类

作用:不能被继承
在这里插入图片描述

修饰成员函数

作用:无法重写
在这里插入图片描述

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

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

相关文章

软件游戏缺失d3dcompiler_47.dll如何解决,简单有效的五种解决方法分享

在现代游戏中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“缺少d3dcompiler47.dll文件”。这个问题通常会导致游戏无法正常运行或出现崩溃的情况。为了解决这个问题&#xff0c;我总结出了以下五种解决方法。希望这些方法能够帮助到遇到相同问题的玩家。 …

web刷题记录(1)

[GXYCTF 2019]Ping Ping Ping 进入页面&#xff0c;发现有一个传入参数的框&#xff0c;目的就是为了让我们通过参数传入内容来执行代码。这里先传入本地ip&#xff0c;方便后面的ping命令运行 ls命令来查看&#xff0c;目录中的文件 传入后&#xff0c;发现目录下有flag.php,…

倍福TwinCAT3 PLC编程软件下载安装

1、哪里下载TwinCAT3 链接: Search result | 倍福 中国https://www.beckhoff.com.cn/zh-cn/support/download-finder/search-result/?download_group=97028248下载倍福PLC编程软件需要注册,大家可以提前注册,注册好后就可以开始愉快的下载了 安装前需要注意将各杀毒软件卸…

单链表经典算法题理解

目录 1. 前言&#xff1a; 2. 移除链表元素 3. 反转链表 4. 合并两个有序链表 5. 链表的中间节点 6. 环形链表的约瑟夫问题 7. 分割链表 1. 前言&#xff1a; 当我们学习了单链表之后&#xff0c;我能可以尝试的刷一下题了&#xff0c;以下分享一下几道题的解法 2. 移…

7-zip工具?这么好用的你都能找到!

关于7-Zip&#xff0c;这不是一个神奇的小工具吗&#xff1f;让我悄悄告诉你&#xff0c;它其实是个压缩界的隐形冠军哦。 想象一下&#xff0c;你下载了一堆文件&#xff0c;电脑空间却告急&#xff0c;这时候7-Zip就像你的小助手&#xff0c;帮你把文件们“瘦身”&#xff0…

【网络运维的重要性】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

期权与股票在交易上是有什么区别吗?

国内的股票市场&#xff0c;只能做多&#xff0c;T1交易。期权则分为4个方向&#xff0c;买入看涨期权&#xff0c;买入看跌期权&#xff0c;也就是做多和做空T0双向交易&#xff0c;同时每个方向还区分不同的行权价&#xff0c;每个行权价对应的4个方向的期权&#xff0c;都有…

AI大模型日报#0529:杨红霞创业入局“端侧模型”、Ilya左膀右臂被Claude团队挖走

导读&#xff1a;AI大模型日报&#xff0c;爬虫LLM自动生成&#xff0c;一文览尽每日AI大模型要点资讯&#xff01;目前采用“文心一言”&#xff08;ERNIE 4.0&#xff09;、“零一万物”&#xff08;Yi-34B&#xff09;生成了今日要点以及每条资讯的摘要。欢迎阅读&#xff0…

springboot+minio 文件上传

前期准备 需要先安装minio文件服务器&#xff0c;请参考我上一篇文章 pom.xml 版本 本次使用的是springboot2.7.16 版本&#xff0c; minio 版本是8.2.2 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-pare…

信息学奥赛初赛天天练-15-阅读程序-深入解析二进制原码、反码、补码,位运算技巧,以及lowbit的神奇应用

更多资源请关注纽扣编程微信公众号 1 2021 CSP-J 阅读程序1 阅读程序&#xff08;程序输入不超过数组或字符串定义的范围&#xff1b;判断题正确填 √&#xff0c;错误填&#xff1b;除特 殊说明外&#xff0c;判断题 1.5 分&#xff0c;选择题 3 分&#xff09; 源码 #in…

debian11安装留档@VirtualBox

因为debian12无法安装tpot&#xff0c;所以又把11重新安装一遍&#xff0c;以前的安装文档&#xff1a;安装Debian 11 留档-CSDN博客 下载光盘 华为云地址&#xff1a;https://repo.huaweicloud.com/debian-cd/11.0.0/amd64/iso-cd/ 使用了debian11 教育版&#xff0c;比较有…

【第7章】SpringBoot整合Mybatis-Plus

文章目录 前言一、引入库二、案例1.UserMapper2.UserController3. 结果 三、配置总结 前言 MyBatis-Plus 是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 上一篇内容已经整合过Mybatis&#xff0c;这里在…

车载电子电器架构 —— 智能座舱标准化意义

车载电子电器架构 —— 智能座舱标准化意义 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消…

11.RedHat认证-Linux文件系统(中)

11.RedHat认证-Linux文件系统(中) Linux的文件系统 格式化分区(1道题) #对于Linux分区来说&#xff0c;只有格式化之后才能使用&#xff0c;不格式化是无法使用的。 #Linux分区格式化之后就会变成文件系统&#xff0c;格式化的过程相当于对分区做了一个文件系统。 #Linux常见…

Linux搭建PHP下的RabbitMQ环境(php-amqp/rabbitmq-c/erlang)

本文演示环境 Red Hat 11.2.1-9gcc (GCC) 11.2.1 20220127OpenSSL v1.1.0PHP 7.1 安装erlang erlang和RabbitMQ有版本对应关系Erlang Version Requirements&#xff0c;需要选择正确的版本。 本文以erlang 26和RabbitMQ 3.13.2为例。 erlang下载地址 下载包上传服务器后&a…

【介绍下运维开发】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

每日复盘-20240529

20240529 六日涨幅最大: ------1--------300956--------- 英力股份 五日涨幅最大: ------1--------301361--------- 众智科技 四日涨幅最大: ------1--------301361--------- 众智科技 三日涨幅最大: ------1--------300637--------- 扬帆新材 二日涨幅最大: ------1--------30…

el-pagination在删除非第一页的最后一条数据遇到的问题

文章目录 前言一、问题展示二、解决方案三、源码解析1、elementui2、elementplus 总结 前言 这个问题是element-ui中的问题&#xff0c;可以从源码中看出来&#xff0c;虽然页码更新了&#xff0c;active也是对的&#xff0c;但是未调用current-change的方法&#xff0c;这里就…

爬虫案例(读书网)

一.我们还是使用简单的bs4库和lxml&#xff0c;使用xpath&#xff1a; 导入下面的库&#xff1a; import requests from bs4 import BeautifulSoup from lxml import etree 我们可以看见它的div和每个书的div框架&#xff0c;这样会观察会快速提高我们的简单爬取能力。 二.实…

Element-UI 入门指南:从安装到自定义主题的详细教程

Element-UI 是一个基于 Vue.js 的前端组件库&#xff0c;它提供了丰富的 UI 组件&#xff0c;可以帮助开发者快速构建高质量的用户界面。以下是使用 Element-UI 的快速入门指南&#xff1a; 安装 Element-UI Element-UI 是一个基于 Vue.js 的组件库&#xff0c;它提供了丰富的…