C++之多态的深度剖析
目录
前言
1.多态的概念
2.多态的定义及实现
2.1多态的构成条件
2.1.1重要条件
2.1.2 虚函数
2.1.3 虚函数的重写/覆盖
2.1.4 选择题
2.1.5 虚函数其他知识
协变(了解)
析构函数的重写
override 和 final关键字
3. 重载,重写,隐藏的对比
4.纯虚函数和抽象类
结束语
前言
在前面我们对C++的封装,继承等特性都有了了解和学习,接下来我们将对C++的第三大特性-多态进行认识和掌握。内容分为来两大部分,第一个是对多态的认识和运用,第二大部分是对多态原理的了解和扩展。
1.多态的概念
多态(Polymorphism)是面向对象编程(OOP)中的一个核心概念,它指的是同一个行为具有多个不同表现形式或形态的能力。在编程中,多态通常通过继承(inheritance)和接(interfaces来实现。
以下是多态的几个主要方面:
-
编译时多态(静态多态):这是在编译时确定的多态性,通常通过函数重载(function overloading)和模板(templates)来实现。编译器根据函数的参数类型或数量来决定调用哪个函数。
-
运行时多态(动态多态):这是在程序运行时确定的多态性,主要通过虚函数(virtual functions)和继承来实现。在运行时,根据对象的实际类型来调用相应的成员函数。
多态的关键特性包括:
- 继承:子类继承父类的属性和行为,可以对这些行为进行重写(override)。
- 虚函数:在基类中声明为虚的成员函数,可以在派生类中被重写,使得通过基类指针或引用调用函数时,能够根据对象的实际类型来调用相应的函数版本。
- 虚函数表:用于实现运行时多态的数据结构,它存储了虚函数的地址,使得程序能够在运行时确定调用哪个函数。
- 向上转型:将派生类对象的引用或指针转换为基类类型的引用或指针,这是多态实现的基础。
2.多态的定义及实现
2.1多态的构成条件
2.1.1重要条件
2.1.2 虚函数
class Person {
public:virtual void BuyTicket() {cout << "买票全额" << endl;}
};
2.1.3 虚函数的重写/覆盖
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Person {
public:virtual void BuyTicket() {cout << "买票全额" << endl;}
};
class Student : public Person {
public:virtual void BuyTicket() {cout << "学生票半价" << endl;}
};
//引用调用
void func(Person& p) {p.BuyTicket();
}
//指针调用
void func1(Person* p) {p->BuyTicket();// 这⾥可以看到虽然都是Person指针Ptr在调⽤BuyTicket// 但是跟ptr没关系,⽽是由ptr指向的对象决定的。
}
int main() {Person p1;Student s1;Person* p2 = new Person();Student* s2 = new Student();func(p1);func(s1);p1.BuyTicket();s1.BuyTicket();func1(&p1);func1(&s1);p2->BuyTicket();s2->BuyTicket();return 0;
}
void func(Student& p) {
p.BuyTicket();
}
//指针调用
void func1(Student* p) {
p->BuyTicket();
}
如果改成Student,就会出问题,就不是多态了,也就不能传Person对象了。
#include <iostream>
using namespace std;class Pet {
public:virtual void eat() const{cout << "Eat food" << endl;}
};
class Dog : public Pet{
public:virtual void eat() const {cout << "Dog eats meat!" << endl;}
};
class Cat :public Pet {
public:virtual void eat()const {cout << "Cat eats fish!" << endl;}
};
void func(const Pet& p) {p.eat();
}
int main() {Pet p;Dog g;Cat c;func(p);func(g);func(c);return 0;
}
上述是宠物的一个多态实现。
这里我们测试一下,基类函数不加virtual会怎样,
class Pet {
public:
void eat() const{
cout << "Eat food" << endl;
}
};
我们会发现多态效果没有实现,所以一定要加上virtual.
2.1.4 选择题
下面程序输出结果是什么?(B)
class A {public:virtual void func(int val = 1){ std::cout<<"A->"<< val <<std::endl;}virtual void test(){ func();}};class B : public A {public:void func(int val = 0){ std::cout<<"B->"<< val <<std::endl; }};int main(int argc ,char* argv[]) {B*p = new B;p->test();return 0; }
B* p = new B;
创建了一个B
类型的对象,并通过基类指针p
指向它。p->test();
调用了A
类的test
方法(因为B
类没有重写test
方法)。- 在
A
类的test
方法中,func(val)
被调用,没有指定val
的值,因此它使用A
类func
方法的默认参数1
。 - 由于
func
是虚函数,并且p
指向一个B
类型的对象,所以B
类的func
方法被调用,接收到的参数是1
。
2.1.5 虚函数其他知识
协变(了解)
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;class A {};
class B : public A {};
class Person {
public:virtual A* BuyTicket(){cout << "买票-全价" << endl;return nullptr;}
};
class Student : public Person {
public:virtual B* BuyTicket(){cout << "买票-打折" << endl;return nullptr;}
};
void Func(Person* ptr)
{ptr->BuyTicket();
}
int main()
{Person ps;Student st;Func(&ps);Func(&st);return 0;
}
析构函数的重写
故在C++中,当一个基类的析构函数被声明为虚函数时,它确保了当通过基类指针或引用删除派生类对象时,会调用正确的析构函数,即派生类的析构函数,然后再调用基类的析构函数。这是因为虚析构函数允许动态绑定,确保了派生类对象被正确地销毁。
#include <iostream>
using namespace std;
class A {
public:virtual ~A() {cout << "delete A" << endl;}
};
class B :public A {public:~B() {cout << "~B()->delete:" << _p << endl;delete _p;}
protected:int* _p = new int[10];
};
int main() {A* a = new A;A* b = new B;delete a;delete b;return 0;
}
当我们不把基类析构函数设置成virtual时, 会发现没有调用B的析构,该释放的资源没有释放掉。
public:~A() {cout << "delete A" << endl;}
};
故基类的析构函数我们要设置成虚函数。
override 和 final关键字
override 关键字用于明确指出一个成员函数旨在重写(覆盖)其基类中的一个虚函数。如果该函数没有正确地重写基类中的任何虚函数,编译器将报错。这有助于避免因拼写错误或参数列表不匹配而意外地没有重写虚函数的情况。
class Car {public:virtual void Dirve(){}};class Benz :public Car {public:virtual void Drive() override { cout << "Benz-舒适" << endl; }};
比如上面这个例子,函数名写错了,重写失败,编译报错。
final 关键字用于防止类被进一步派生,或者防止虚函数被重写。当应用于类时,它表示这个类不能被继承。当应用于虚函数时,它表示这个虚函数不能在派生类中被重写。
class Car {
public:virtual void Dirve() final{}
};
class Benz :public Car {
public:virtual void Dirve(){ cout << "Benz-舒适" << endl; }
};
class Base final { // 不能从这个类派生其他类
public:
virtual void doSomething() const final {} // 这个虚函数不能被重写
};
// 下面的类声明会导致编译错误,因为 Base 是 final 的
// class Derived : public Base {};
// 下面的函数声明也会导致编译错误,因为 doSomething 是 final 的
// class Derived : public Base {
// public:
// void doSomething() const override {} // 错误:不能重写 final 函数
// };
使用 final 关键字可以确保类或虚函数的行为不会被意外的继承或重写改变,这对于设计那些不打算被扩展的类或函数非常有用。
3. 重载,重写,隐藏的对比
重载(Overloading)
- 定义:在同一作用域内,可以定义多个同名函数,只要它们的参数列表(参数的数量、类型或顺序)不同。
- 特点:
- 发生在同一类中。
- 参数列表必须不同。
- 返回类型可以不同,但不是区分重载的主要因素。
重写(Overriding)
- 定义:在派生类中提供一个与基类中虚函数同名、参数列表和返回类型相同的函数,以实现多态。
- 特点:
- 发生在基类和派生类之间。
- 参数列表和返回类型必须相同。
- 基类函数必须是虚函数。
- 使用
override
关键字可以明确指出重写意图。
隐藏(Hiding)
- 定义:在派生类中定义一个与基类中成员(非虚函数或非静态成员变量)同名的成员,导致基类中的同名成员在派生类中不可见。
- 特点:
- 发生在基类和派生类之间。
- 可以是函数或变量。
- 如果是函数,参数列表不必相同。
- 如果派生类中的成员与基类中的成员具有相同的名称,但不同的参数列表,则基类成员被隐藏,而不是重载或重写。
4.纯虚函数和抽象类
#include <iostream>
using namespace std;
class Car {
public:virtual void Drive() = 0;};
class Benchi :public Car {
public:virtual void Drive() {cout << "Benchi-舒适" << endl;}
};class Baoma :public Car {
public:virtual void Drive() {cout << "Baoma-上手" << endl;}
};
int main() {Car car;Car* b = new Benchi();b->Drive();Car* m = new Baoma();m->Drive();return 0;
}
这里Car是抽象类,所以无法实例化对象。
结束语
本期内容就到此结束了,内容有点多,下节我们将对多态的原理进行补充讲解。
最后感谢各位友友的支持!!!
相关文章:
C++之多态的深度剖析
目录 前言 1.多态的概念 2.多态的定义及实现 2.1多态的构成条件 2.1.1重要条件 2.1.2 虚函数 2.1.3 虚函数的重写/覆盖 2.1.4 选择题 2.1.5 虚函数其他知识 协变(了解) 析构函数的重写 override 和 final关键字 3. 重载,重写&…...
Microsoft Office PowerPoint制作科研论文用图
Microsoft Office PowerPoint制作科研论文用图 1. 获取高清图片2. 导入PPT3. 另存为“增强型windows元文件”emf格式4. 画图剪裁 1. 获取高清图片 这里指通过绘图软件画分辨率高的图片,我一般使用python画dpi600的图片。 2. 导入PPT 新建一个PPT(注意&a…...
go语言进阶之并发基础
并发 什么是并发,也就是我们常说的多线程,多个程序同时执行。 并发的基础 线程和进程 进程 进程是操作系统中一个重要的概念,指的是一个正在运行的程序的实例。它包含程序代码、当前活动的状态、变量、程序计数器和内存等资源。进程是系…...
po、dto、vo的使用场景
现在项目中有两类模型类:DTO数据传输对象、PO持久化对象,DTO用于接口层向业务层之间传输数据,PO用于业务层与持久层之间传输数据,有些项目还会设置VO对象,VO对象用在前端与接口层之间传输数据,如下图&#…...
聊一聊Elasticsearch的一些基本信息
一、Elasticsearch是什么 Elasticsearch简称ES,是一款分布式搜索引擎。它是在Apache Lucene基础之上采用Java语言开发的。 Elasticsearch的官方网站对它的解释是:Elasticsearch是一个分布式、RESTful的搜索和数据分析引擎。 通过上边的官方解释&#…...
Unity 两篇文章熟悉所有编辑器拓展关键类 (上)
本专栏基础资源来自唐老狮和siki学院,仅作学习交流使用,不作任何商业用途,吃水不忘打井人,谨遵教诲 编辑器扩展内容实在是太多太多了(本篇就有五千字) 所以分为两个篇章而且只用一些常用api举例,…...
Spring SPI、Solon SPI 有点儿像(Maven 与 Gradle)
一、什么是 SPI SPI 全名 Service Provider interface,翻译过来就是“服务提供接口”。基本效果是,申明一个接口,然后通过配置获取它的实现,进而实现动态扩展。 Java SPI 是 JDK 内置的一种动态加载扩展点的实现。 一般的业务代…...
合并排序算法(C语言版)
#include <stdio.h> void Copy(int *a, int *b, int left, int right) { int i; for(i0;i<right-left1;i) { a[ileft] b[i]; } } // 将 a[left,middle] 和 a[middle1,right]合并到 b[left, right]中 void Merge(int *a, int left, int midd…...
C++——输入一行文字,找出其中的大写字母、小写字母、空格数字以及其他字符各有多少。用指针或引用方法处理。
没注释的源代码 #include <iostream> using namespace std; int main() { char c; int ul0,ll0,sp0,di0,other0; cout<<"please input script c:"; while(cin.get(c)) { if(c\n) break; else if(c>A&&…...
【skywalking】maximum query complexity exceeded 3336 > 3000
问题 skywalking相关版本信息 jdk:17skywalking:10.1.0apache-skywalking-java-agent:9.3.0ElasticSearch : 8.8.2 问题描述 maximum query complexity exceeded 3336 > 3000 最大查询复杂度超过3336>3000 可能原因 查询条件过于复…...
开源一个开发的聊天应用与AI开发框架,集成 ChatGPT,支持私有部署的源码
大家好,我是一颗甜苞谷,今天分享一个开发的聊天应用与AI开发框架,集成 ChatGPT,支持私有部署的源码。 介绍 当前系统集成了ChatGPT的聊天应用,不仅提供了基本的即时通讯功能,还引入了先进的AI技术&#x…...
开发了一个成人学位英语助考微信小程序
微信小程序名称:石榴英语 全称:石榴英语真题助手 功能定位 北京成人学士学位英语辅助学习工具,包含记高频单词,高频词组,专项练习,模拟考试等功能。 开发背景 个人工作需要提高学习英文水平ÿ…...
LeetCode16:最接近的三数之和
原题地址:. - 力扣(LeetCode) 题目描述 给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。 返回这三个数的和。 假定每组输入只存在恰好一个解。 示例 1…...
VisualStudio2022配置2D图形库SFML
文章目录 1. 下载安装SFML库2. 创建C项目并配置SFML配置include目录和库目录链接SFML库配置动态链接库 3. 测试 1. 下载安装SFML库 SFML(Simple and Fast Multimedia Library)C库,适合2D游戏和图形界面,提供了以下模块࿱…...
「Mac畅玩鸿蒙与硬件4」鸿蒙开发环境配置篇4 - DevEco Studio 高效使用技巧
本篇将进一步介绍如何在 DevEco Studio 中高效使用各种功能,通过掌握快捷键、代码补全、调试工具等,帮助开发者在鸿蒙应用开发中大幅提升工作效率。 关键词 DevEco Studio快捷键代码补全调试工具项目导航 一、快捷键与高效操作 快捷键是提升开发效率的…...
构建生产级的 RAG 系统
对 RAG 应用程序进行原型设计很容易,但要使其高性能、健壮且可扩展到大型知识语料库却很困难。 本指南包含各种提示和技巧,以提高 RAG 工作流程的性能。我们首先概述一些通用技术 - 它们按照简单到复杂的顺序进行排列。然后,我们将更深入地研…...
完全透彻了解一个asp.net core MVC项目模板2
这是《完全透彻了解一个asp.net core MVC项目模板》的第二篇,如果你直接进入了本篇博文而不知道上下文,请先阅读《完全透彻了解一个asp.net core MVC项目模板》的第一篇。 文章目录 一、补充几个问题1、有关导航链接和Tag Helper2、_ViewStart.cshtml与…...
uniapp 如何调用音频
uniapp调用音频 button点击 <view><button click"startPlay">开始播放</button></view>方法实现 startPlay() { const innerAudioContext uni.createInnerAudioContext();innerAudioContext.src /static/sounds/oqc.mp3;innerAudioContex…...
在Facebook运营中使用住宅IP的重要性
在当前社交媒体的浪潮中,Facebook作为全球最大的社交网络之一,吸引了数以亿计的用户。为了在这一平台上实现有效的运营和推广,越来越多的博主和营销人员正在寻求最佳的养号策略。其中,IP地址的选择显得尤为重要,尤其是…...
EJB项目如何升级SpringCloud
记录某金融机构老项目重构升级为微服务过程1 如何从EJB架构拆分微服务 这个非常有趣的过程,整个过程耗时大致接近半年时光,需要考虑到重构升级保留原来的业务线,而且还要考虑后续的维护成本,保留现有的数据库表结构,…...
HTTPS 协议原理
一.HTTPS的定义 大家在刚开始学习的时候是不是也是非常好奇HTTP与HTTPS之间有什么区别和联系,两者都是应用层协议,而HTTPS是在HTTP的基础上引入了加密层,从而将HTTP的明文传输进行加密,保障数据的安全性 二.加密与解密 定义&#…...
Vxe UI 表格行编辑(默认不显示编辑框,点击后可编辑)
效果: HTML代码:(type"integer"为这个,是限制只能输入正整数或负整数,英文和汉字自动转成0) <vxe-tableshow-overflowkeep-sourcev-loading"loading":data"ruleList"ref"Table":row-config"{isHover: true}"height"…...
移远通信闪耀2024香港秋灯展,以丰富的Matter产品及方案推动智能家居产业发展
10月27-30日,2024香港国际秋季灯饰展在香港会议展览中心盛大开展。 作为全球领先的物联网整体解决方案供应商,移远通信再次亮相,并重点展示了旗下支持Matter协议以及亚马逊ACK ( Alexa Connect Kit ) SDK for Matter方案的Wi-Fi模组、低功耗蓝…...
爬虫利器playwright
是什么 它是微软在 2020 年初开源的新一代自动化测试工具,其功能和 selenium 类似,都可以驱动浏览器进行各种自动化操作。还可以录制脚本 案列-01 运行之后我们用它自动打开的谷歌浏览器,打开百度,输入漂亮小姐姐并查找&#x…...
着色器的认识
知识了解: 着色器: 顶点着色器: 用来描述顶点的特性,如位置、颜色等,其中,顶点:是指二维或三维空间中的一个点比如交点或者端点。 片元着色器:用来进行逐片元处理操作,比如光照、颜色叠加等&…...
科技的成就(六十四)
591、《传奇》开始公开测试 "2001 年 9 月,《传奇》开始公开测试。《传奇》(全称《热血传奇》)是由韩国 WeMade 娱乐开发制作的大型多人在线角色扮演游戏,由 Delphi 编写。盛大网络于2001 年获得该游戏在中国的代理权。《传奇…...
银行信贷风控专题:Python、R 语言机器学习数据挖掘应用实例合集:xgboost、决策树、随机森林、贝叶斯等...
全文链接:https://tecdat.cn/?p38026 分析师:Fanghui Shao 在当今金融领域,风险管控至关重要。无论是汽车贷款违约预测、银行挖掘潜在贷款客户,还是信贷风控模型的构建,以及基于决策树的银行信贷风险预警,…...
〈壮志凌云:独行侠〉中的超高音速战机
电影《壮志凌云:独行侠》中使用的黑星(Darkstar)高超音速概念战机模型,虽然看起来像是科幻电影里的产物,但这架飞机实际上是由洛克希德马丁公司的臭鼬工厂(Skunk Works)设计,这是一家…...
k8s集群 ceph rbd 存储动态扩容
k8s 集群 rbd 扩容有两种方法,如下所示 通过StorageClass自动扩容 # kubectl get sc csi-rbd-sc -oyaml|grep allowVolumeExpansion allowVolumeExpansion: true如果搜索有如上字段,说明是可以自动扩容的,修改对应要扩容的 PVC容量…...
C语言笔记(指针题目)例题+图解
本文分为两部分 ,第一部分为数组、字符串、字符指针在sizeof和strlen中的辨析,第二部分是一些笔试题目。若有错误,请批评指正。 目录 1.第一部分 1.1.数组名的使用 1.1.1一维整型数组在sizeof中的使用 1.1.2一维字符数组在sizeof中的使用…...
沈阳网站关键词优化多少钱/网页制作模板
摘要:伴随信息技术的快速发展,进一步促进水厂的信息系统化建设成为水厂管理工作的重中之重。依据水厂管理工作的实际业务需求,设计与实现基于B/S的水厂管理信息系统具有现实需求,同时也具有较高的实际性价值和必要性。本系统的设计与实现过程可划分为:需求分析、系统…...
Vps wordpress https/百度网站推广费用多少
一、什么是JAVA的消息服务 上文中我们提到Java消息服务指的是两个应用程序之间进行异步通信的API,它为标准消息协议和消息服务提供了一组通用接口,包括创建、发送、读取消息等,用于支持JAVA应用程序开发。在J2EE中,当两个应用程序…...
网站开发经济可行性分析/武汉seo搜索引擎优化
内网穿透 一、介绍 1.概念 内网穿透简单来说就是将内网外网通过natapp隧道打通,让内网的数据让外网可以获取。比如常用的办公室软件等,一般在办公室或家里,通过拨号上网,这样办公软件只有在本地的局域网之内才能访问,那么问…...
网站建设与管理模拟题1/小型培训机构管理系统
从HTML被发明开始,样式就以各种形式存在。不同的浏览器结合它们各自的样式语言为用户提供页面效果的控制。最初的HTML只包含很少的显示属性。随着HTML的成长,为了满足页面设计者的要求,HTML添加了很多显示功能。但是随着这些功能的增加&#…...
网站制作方法/网站seo置顶
2014年9月19日,阿里巴巴成功上市,成为美国史上IPO数额最大的公司,一夜间成为世界第二大互联网公司,其市值首日即超过美国最大电商亚马逊加EBay之和。 阿里巴巴路演IPO时每股估值不过68美元,而首日收盘价达到每股93.89…...
可以做四级听力的网站/如何发布一个网站
2019独角兽企业重金招聘Python工程师标准>>> jQuery在1.7以后,添加了.one()方法。表示在元素上某个事件只能触发一次,并且绑定事件。 如: $(#id).one(click, function(){$(this).css(color,red);//改变元素样式}); 相当于&#…...