当前位置: 首页 > news >正文

C++基础讲解第六期(多态、虚函数、虚析构函数、dynamic_cast、typeid纯虚函数)

C++基础讲解第六期 代码中也有对应知识注释,别忘看,一起学习!

  • 一、多态
    • 1. 问题引出
    • 2. 多态的概念和使用
    • 3. 多态的原理
    • 4. 虚析构函数
    • 5. 动态类型识别(dynamic_cast)
      • (1) 自定义类型
      • (2). dynamic_cast
      • (3). typeid
    • 6. 纯虚函数
  • 纯虚函数需要补充

一、多态

1. 问题引出

#include<iostream>
using namespace std;class Parent
{public:void show(){cout<<"this is parent"<<endl;}
};class Child : public Parent
{public:void show(){cout<<"this is child"<<endl;}
};int main()
{Child c;Parent p;p = c; //向上转型, 大的赋给小的Parent *p1 = new Child;  //基类指针指向派生类对象p1->show();  //会调用基类的show,是静态联编,编译器会根据p1的类型(Parent*)调用Parent类中的show函数return 0;
}

2. 多态的概念和使用

在基类指针指向基类对象的时候,就使用基类中的方法和属性
在指向派生类对象的时候,就使用派生类中的方法和属性
通俗的说,基类指针可以按照基类的方法来做事,也可以按照派生类的方法来做事,它有多种形态,或者说多种表现方式。
我们将这种现象称为多态。

多态产生的条件:

  1. 要有继承
  2. 要有虚函数重写(发生在不同作用域中,函数原型相同), 派生类中的重写函数前面加不加virtual都可以
  3. 基类指针指向派生类对象
#include<iostream>
using namespace std;class Parent
{public:virtual void show()   //被virtual修饰的函数叫虚函数{cout<<"this is parent"<<endl;}
};class Child : public Parent  //1.要有继承
{public:void show()          //2.要有虚函数重写(发生在不同作用域中,函数原型相同)派生类中的重写函数前面加不加virtual都可以{cout<<"this is child"<<endl;}
};int main()
{Parent *p1 = new Child;   //3.基类指针指向派生类对象p1->show();               //动态联编,运行的时候才知道p1指向什么对象delete p1;p1 = nullptr;p1 = new Parent;          //基类指针指向基类对象,调用的是基类中的方法p1->show();               //相同的语句有不同的执行结果(多态)return 0;
}
result:
this is child
this is parent

总结:
其实多态的作用就是,派生类重写基类中的虚函数, 这样当我们基类指针指向什么类型,那么调用的方法就是指向类型的类中的方法和属性
记住向上转型,只允许基类指针指向派生类对象,基类引用可以引用派生类对象。派生类指针不能指向基类对象, 派生类引用也不能引用基类对象

3. 多态的原理

根据上一期所讲,当我们算大小的时候,存在虚函数表指针,其会占8个字节
所以看到结果不要傻眼

#include<iostream>
using namespace std;class Parent
{public:int a;virtual void show()   //被virtual修饰的函数叫虚函数{cout<<"this is parent"<<endl;}
};class Child : public Parent  //1.要有继承
{public:void show()          //2.要有虚函数重写(发生在不同作用域中,函数原型相同){cout<<"this is child"<<endl;}
};int main()
{Parent p;Child c;cout<<sizeof(p)<<endl;cout<<sizeof(c)<<endl;cout<<"parent对象的地址"<<&p<<endl;cout<<"parent成员变量a的起始地址"<<&p.a<<endl;
}result:
16
16
parent对象的地址0x7fff57881350
parent成员对象的起始地址0x7fff57881358

4. 虚析构函数

根据析构的规则,只能从当前基类开始往上调用析构函数,而并不能调用派生类中的析构函数.
通过将基类中的析构函数设置为虚析构函数,可以通过delete正确的调用析构函数.
也就是我基类指针指向哪个类型, 就先调用那个类中的析构函数
虚析构函数:通过基类指针释放派生类对象

#include<iostream>
using namespace std;class Parent
{public:int a;virtual void show()   //被virtual修饰的函数叫虚函数{cout<<"this is parent"<<endl;}virtual ~Parent(){cout<<"parent 的析构函数"<<endl;}
};class Child : public Parent  //1.要有继承
{public:void show()          //2.要有虚函数重写(发生在不同作用域中,函数原型相同){cout<<"this is child"<<endl;}~Child(){cout <<"child 的析构函数"<<endl;}
};int main()
{Parent *p1 = new Child;p1->show();delete p1;   //释放派生类对象, 虚析构函数:通过基类指针释放派生类对象p1 = nullptr;return 0;
}基类中析构函数不加virtual:
this is child
parent 的析构函数基类中析构函数加上virtual:
this is child
child 的析构函数
parent 的析构函数

5. 动态类型识别(dynamic_cast)

新的关键词: dynamic_cast

  1. dynamic_cast是c++中新关键词
  2. dynamic_cast用于基类和派生类之间的类型转换
  3. dynamic_cast要求使用的目标类型是多态的
    既要求所在类至少有一个虚函数
    用于指针转换时,转换失败返回nullptr
    用于引用转换时,转换失败引发bad_cast异常(异常处理失败,后期会讲)

优势:

  1. 不用显示的声明和定义虚函数
  2. 不用为类族中的每个类分配类型ID

缺点:

  1. 只能用于有虚函数的类

(1) 自定义类型

手动去封装一个函数去实现什么情况可以转换类型,什么情况下不能转发,防止编译器报错

#include<iostream>
using namespace std;class Parent
{private:int a;public:enum{ID = 0};virtual int GetID(){return ID;}
};class Child : public Parent
{public:int array[102400];int a;enum{ID = 1};int GetID(){return ID;}
};void fun(Parent *p)
{//Child *c = (Child *)p;     //使用强转类型,派生类指针指向基类对象if(p->GetID() ==  Child::ID)  //如果成立,说明指向派生类对象{Child* c = (Child*)p;c->array[102400 - 1] = 100;cout<< "转换成功"<<endl;}else{cout << "不能转换" <<endl;}
}int main()
{Parent *p = new Child; //基类指针指向派生类对象,调用的方法是派生类中的方法(多态)fun(p);Parent *p1 = new Parent; //基类指针指向基类对象,调用的方法是基类中的方法(多态)fun(p1);return 0;
}result:
转换成功
不能转换

(2). dynamic_cast

总结: dynamic_cast很优雅, 不像强转类型会造成系统崩溃, 其会去检查是否可以转换类型. 并且不需要我们向上面一样手动去封装一个判断能否转换类型的函数

#include<iostream>
using namespace std;class Parent
{private:int a;public:virtual void show(){}
};class Child : public Parent
{public:int array[102400];void show(){}
};void fun(Parent *p)
{//Child *c = (Child *)p;     //使用强转类型,派生类指针指向基类对象Child *c = dynamic_cast<Child*>(p);  //如果p指向的是基类对象,则转换失败,转换失败返回nullptrif(nullptr == c){cout<<"转换失败"<<endl;}else{c->array[102400 - 1] = 100;cout<<"转换成功"<<endl;}
}int main()
{Parent *p = new Child;  //当我们基类指针指向派生类对象,在fun中进行强转时,是没有问题的fun(p);Parent *p1 = new Parent;fun(p1);return 0;
}
result:
转换成功
转换失败

(3). typeid

typeid运算符用来获取一个表达式的类型信息
typeid的操作对象可以是表达式,也可以是数据类型,使用方法如下:

  1. typeid(data Type);
  2. typeid(expression);

总结:

  1. typeid关键词返回对应参数的类型信息
  2. typeid关键词返回一个type_info类对象
  3. 当typeid参数为NULL时,抛出一个bad_cast异常
  4. 使用type_info类需要包含typeinfo头文件
#include<iostream>
#include<typeinfo>
using namespace std;class Parent
{private:int a;public:virtual void show(){}
};class Child : public Parent
{public:int array[102400];void show(){}
};void fun(Parent* p)
{if(typeid(*p) == typeid(Child)){Child* c = (Child*)p;c->array[102400 - 1] = 100;cout<< "转换成功"<<endl;}else if(typeid(*p) == typeid(Parent)){cout<<"不能转换"<<endl;}
}int main()
{int a;char ch;Parent p1;Child c1;const type_info &pa = typeid(a); const type_info &pb = typeid(ch);const type_info &pc = typeid(p1);const type_info &pd = typeid(c1);cout <<pa.name() <<endl;cout <<pb.name() <<endl;cout <<pc.name() <<endl;cout <<pd.name() <<endl;Parent *p = new Child;fun(p);Parent* p2 = new Parent;fun(p2);result:
i
c
6Parent
5Child
转换成功
不能转换
}

6. 纯虚函数

在c++中,可以将函数声明为纯虚函数,语法格式
virtual 返回值类型 函数名 (函数参数) = 0;
含有纯虚函数的类为抽象类,不能实例化
基类中的纯虚函数不需要实现
并且继承它的派生类必须实现基类的纯虚函数

#include<iostream>
#include<typeinfo>
using namespace std;class Parent  //含有纯虚函数的类称为抽象类,不能实例化
{private:int a;public:virtual void print() = 0;   //纯虚函数没有函数体
};class Child : public Parent
{public:void print(){cout<<"this is child"<<endl;}
};int main()
{//Parent p; // p.print();Parent *p = new Child; //可以创建子类对象,基类为抽象类,不能实例化对象p->print();}

纯虚函数需要补充

相关文章:

C++基础讲解第六期(多态、虚函数、虚析构函数、dynamic_cast、typeid纯虚函数)

C基础讲解第六期 代码中也有对应知识注释&#xff0c;别忘看&#xff0c;一起学习&#xff01; 一、多态1. 问题引出2. 多态的概念和使用3. 多态的原理4. 虚析构函数5. 动态类型识别(dynamic_cast)(1) 自定义类型(2). dynamic_cast(3). typeid 6. 纯虚函数 纯虚函数需要补充 一…...

防火墙之iptables(二)

防火墙之iptables&#xff08;二&#xff09; 一.SNAT原理与应用 1.应用环境 局域网主机共享单个公网IP地址接入Internet&#xff08;私网不能被Internet中正常路由&#xff09;2.SNAT原理 修改数据包的源地址内网访问外网 将从内网发送到外网的数据包的源IP由私网IP转换成…...

亚马逊销量暴跌该如何查找原因?

很多卖家经常遇到一个棘手的问题&#xff0c;就是突然会遇到链接销量暴跌的问题。 比如之前链接可以稳定出单10多单的&#xff0c;突然连续几天只有两三单&#xff0c;这到底是什么原因呢? 1.查看链接的类目是否被修改 这个类目修改不一定是卖家自己修改&#xff0c;更多的时…...

Vue中的脚手架和路由

私人博客 许小墨のBlog —— 菜鸡博客直通车 系列文章完整版&#xff0c;配图更多&#xff0c;CSDN博文图片需要手动上传&#xff0c;因此文章配图较少&#xff0c;看不懂的可以去菜鸡博客参考一下配图&#xff01; 系列文章目录 前端系列文章——传送门 后端系列文章——传送…...

Convolutional Neural network(卷积神经网络)

目录 Why CNN for Image&#xff1f; The whole CNN structure Convolution&#xff08;卷积&#xff09; Max Pooling Flatten CNN in Keras What does CNN learn&#xff1f; what does filter do what does neuron do what about output Deep Dream Application Pla…...

【资料分享】高边、低边晶体管开关及电路解析

高边和低边晶体管开关 电路中&#xff0c;晶体管常常被用来当做开关使用。晶体管用作开关时有两种不同的接线方式&#xff1a;高边&#xff08;high side&#xff09;和低边(low side)。 高边和低边是由晶体管在电路中的位置决定的。晶体管可以是双极性晶体管&#xff08;BJT…...

六级备考28天|CET-6|听力第二讲|长对话满分技巧|听写技巧|2022年6月考题|14:30~16:00

目录 1. 听力策略 2. 第一二讲笔记 3. 听力原文复现 (5)第五小题 (6)第六小题 (7)第七小题 (8)第八小题 扩展业务 expand business 4. 重点词汇 1. 听力策略 2. 第一二讲笔记 3. 听力原文复现 (5)第五小题 our guest is Molly Sundas, a university stud…...

计算机图形学 | 实验九:纹理贴图和天空盒

计算机图形学 | 实验九&#xff1a;纹理贴图和天空盒 计算机图形学 | 实验九&#xff1a;纹理贴图和天空盒实验概述顶点数据立方体顶点数据天空盒顶点数组 纹理载入创建纹理纹理读取纹理绑定 使用纹理立方体着色器顶点着色器片元着色器 天空盒着色器顶点着色器片元着色器 立方体…...

Unity A* Pathfinding Project

先下载免费版 https://arongranberg.com/astar/download# 教程首页 https://arongranberg.com/astar/docs/getstarted.html 创建一个plane 当地面 创建一个gameobject 添加组件 PathFinder 长这样 调整每个格子大小的 创建两个layer 一个是阻挡物的 一个是地面的 这里填入阻…...

SpringBoot ( 一 ) 搭建项目环境

1.搭建环境 1.1.创建项目向导 使用idea中的向导创建SpringBoot项目 1.1.1.建立新的项目 位置 : 菜单 > File > New > Project… 1.1.2.选择向导 默认的向导URL 是 https://start.spring.io 建议使用 https://start.aliyun.com 1.1.3.配置项目信息 Group : 组织…...

idea中关联Git

注意&#xff1a;未安装和配置Git软件&#xff0c;请先跳转到 Git宝典_没办法&#xff0c;我就是这么菜的博客-CSDN博客 idea关联git 关联git.exe 选择你的Version Control 下的Git 选择你的Git安装目录bin下的git.exe&#xff0c;点击ok 点击Test&#xff0c;显示版本号…...

Java面试知识点(全)-分布式微服务-zookeeper面试知识点

Java面试知识点(全) 导航&#xff1a; https://nanxiang.blog.csdn.net/article/details/130640392 注&#xff1a;随时更新 ZooKeeper是什么&#xff1f; ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Google的Chubby一个开源的实现&…...

(IDEA)springCloud项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案

idea导入本地jar包 方法一:点击左上角File–>Project Structure–>Modules。打开Modules界面点击下方号&#xff0c;选择第一项&#xff0c;找到想要导入的本地jar包。此方法可以使项目使用导入的jar包程序不报错&#xff0c;但是在打包项目时&#xff0c;会出现找不到程…...

非线性系统的线性化与泰勒级数

线性系统与非线性系统的区别 我们在读论文的时候经常会遇到这两个系统&#xff0c;线性系统与非线性系统&#xff0c;这两者之间有什么区别呢&#xff1f; 线性指量与量之间按比例、成直线的关系&#xff0c;在空间和时间上代表规则和光滑的运动&#xff1b;非线性则指不按比…...

HOOPS全新文档系统上线!三维模型文件转换更便捷!

HOOPS 2023 U1版本已经正式发布&#xff0c;伴随新版本上线的还有全新的文档系统&#xff0c;新的文档系统亮点包括&#xff1a; 改进了样式和布局&#xff0c;使导航更加简单快捷&#xff1b;修订了导航结构&#xff0c;提高了产品相关信息的清晰度&#xff1b;SDK API参考章…...

第三篇:强化学习发展历史

你好&#xff0c;我是zhenguo&#xff08;郭震&#xff09; 这是强化学习第三篇&#xff0c;我们回顾一下它的发展历史&#xff1a;强化学习发展历史 强化学习作为一门研究领域&#xff0c;经历了多年的发展和演进。以下是强化学习的主要发展历史里程碑&#xff1a; 1950年代-1…...

如何学会战略性思维?

上帝在创造一个成功人生时加入了什么配方&#xff1f;一部分努力、一点天赋、必备的人脉、再加入不可或缺的good luck......这都是成功人生的重要因素。 弗雷德佩拉德认为&#xff0c;不管人们在商业领域选择追求什么&#xff0c;要想成功&#xff0c;还需要增加一个名为“战略…...

设备采购信息管理系统

系列文章 任务14 设备采购信息管理系统 文章目录 系列文章一、实践目的与要求1、目的2、要求 二、课题任务三、总体设计1.存储结构及数据类型定义2.程序结构3.所实现的功能函数4、程序流程图 四、小组成员及分工五、 测试界面展示添加采购信息按编号查找采购信息按设备编号查找…...

Puppeteer入门实践

环境 1、安装nodejs 官网&#xff1a;https://nodejs.org/zh-cn 下载安装好nodejs只后 验证&#xff1a;node -v 出现版本号表示安装成功&#xff0c;否则需要配置环境变量 2、创建node项目并初始化 随便新建一个文件夹 进入文件夹搜索cmd回车 执行npm init -y 安装依赖 …...

生成VLC 及其模块的全面帮助

使用vlc.exe -H命令生成VLC帮助文件vlc-help.txt -h, --help, --no-help 打印 VLC 帮助 (可以和 --advanced 和 --help-verbose 一起使用) (默认禁用) -H, --full-help, --no-full-help VLC 及…...

无机布防火卷帘门价格怎么算?按尺寸定制,按需报价

无机布防火卷帘门作为建筑防火分区的核心设备&#xff0c;价格一直是工程采购的关注重点。很多用户在询价时&#xff0c;会发现不同厂家的报价差异较大&#xff0c;这是因为无机布防火卷帘门的价格并非按统一单价计算&#xff0c;而是完全根据项目的实际需求定制化核算。 &…...

别再死记硬背了!用5个生活化比喻彻底搞懂Linux进程的fork、exec和wait

别再死记硬背了&#xff01;用5个生活化比喻彻底搞懂Linux进程的fork、exec和wait想象你正在厨房准备一顿大餐。菜谱上写着"切菜"、"炒菜"、"装盘"等步骤&#xff0c;但突然发现需要同时处理多道菜品——这时候&#xff0c;你会本能地让家人分工…...

Taotoken的审计日志功能为企业API安全与合规管理提供支持

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 Taotoken的审计日志功能为企业API安全与合规管理提供支持 当企业决定将大模型能力集成到内部业务流程中时&#xff0c;IT管理员和安…...

XZ6128A工作电压5-100V 输出电流5A 升压型大功率LED灯恒流驱动控制芯片

概述 XZ6128A是一款高效率、高精度的升压型大功率LED灯恒流驱动控制芯片。 XZ6128A内置高精度误差放大器&#xff0c;固定关断时间控制电路&#xff0c;恒流驱动电路等&#xff0c;特别适合大功率、多个高亮度LED灯串的恒流驱动。 XZ6128A采用固定关断时间的控制方式&#xff0…...

PostgreSQL Merge Join 大白话详解

用生活中最直观的例子&#xff0c;彻底搞懂 Merge Join 是什么、为什么快、什么时候用。一、先从生活场景开始 场景一&#xff1a;两摞乱序试卷找同学 期末考试&#xff0c;老师手里有两摞试卷&#xff1a; A 摞&#xff1a;数学试卷&#xff0c;500 份&#xff0c;乱序堆放B 摞…...

ThingLinks-IoT:一站式物联网平台解决方案

ThingLinks-IoT 物联网平台 | 多协议接入物模型告警联动视频接入AI 助手 一体化方案 一个面向项目交付与企业生产场景的国产物联网中台——把"设备接入 → 数据处理 → 告警联动 → 业务集成"这条链路上的通用能力一次性做完做稳&#xff0c;让你只关心自己的业务。 …...

3个核心问题:如何突破Cursor AI的使用限制并持续获得Pro功能体验?

3个核心问题&#xff1a;如何突破Cursor AI的使用限制并持续获得Pro功能体验&#xff1f; 【免费下载链接】cursor-free-vip [Support 0.45]&#xff08;Multi Language 多语言&#xff09;自动注册 Cursor Ai &#xff0c;自动重置机器ID &#xff0c; 免费升级使用Pro 功能: …...

从《原神》到独立游戏:聊聊URP相机Stack(Overlay)如何实现那些酷炫的UI与特效

从《原神》到独立游戏&#xff1a;URP相机堆叠技术如何重塑游戏视觉表现当你在《原神》中打开地图界面时&#xff0c;是否注意到背景世界依然保持着动态光影效果&#xff1f;当角色受伤时&#xff0c;那层红色渐隐特效为何能如此自然地覆盖在3D场景之上&#xff1f;这些看似简单…...

基于傅里叶神经算子的含时密度泛函理论加速模拟

1. 项目概述与核心思路在计算材料科学和量子化学领域&#xff0c;模拟电子在激光等外场驱动下的动力学行为&#xff0c;是理解光催化、光电转换、甚至量子计算基础过程的关键。含时密度泛函理论&#xff08;TDDFT&#xff09;是处理这类问题的“金标准”之一&#xff0c;它通过…...

3分钟从视频中提取PPT:告别手动截图的全自动方案

3分钟从视频中提取PPT&#xff1a;告别手动截图的全自动方案 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 你是否曾为从会议录像、在线课程或培训视频中提取PPT页面而烦恼&#xf…...