C++多态的理解
C++多态的理解
- 1 C++多态的概念
- 2 C++多态的类型
- 3 虚函数实现多态案例分析
- 3.1 非虚函数成员函数调用的案例
- 3.1.1 测试代码
- 3.1.2 测试运行结果
- 3.2 虚函数成员函数调用案例
- 3.2.1 虚函数实现测试代码
- 3.2.2 测试运行结果
- 3.3 基类析构函数的实现
- 3.3.1 析构函数定义和实现案例
- 3.3.2 基类析构函数采用虚函数实现的原因
- 3.4 纯虚函数
1 C++多态的概念
C++多态是面向对象编程中的一个重要概念,它允许同一个接口或父类引用可以指向多种实际类型,并且可以根据实际类型来调用相应的方法。多态的存在可以使程序具有更好的灵活性和可维护性,同时减少代码的重复性。
多态的实现主要基于继承、重写和对象指针或引用来实现。继承允许一个类继承另一个类的属性和方法,而重写则允许子类重新定义从父类中继承的方法,以满足自身的需求。通过使用父类引用来指向子类对象,我们可以在运行时确定实际调用的方法,从而实现多态。
在C++中,多态主要通过虚函数来实现。虚函数是在基类中使用关键字virtual声明的成员函数,它可以在派生类中被重写。通过在派生类中重写虚函数,可以改变基类中的方法实现逻辑,使其适应派生类的需求。然后,通过使用基类指针或引用指向派生类对象,可以调用虚函数,并根据实际类型来调用相应的方法。这个过程称为动态绑定或延迟绑定。
除了虚函数,构造函数重载和类型多态性也可以实现多态。构造函数多态性允许我们在创建派生类对象时调用基类构造函数,并在其中添加派生类的初始化代码。类型多态性则允许我们使用基类指针或引用调用派生类的方法,这些方法可以在运行时动态地绑定到正确的对象上。
需要注意的是,多态的实现需要适当的条件。首先,父类中必须声明虚函数,以便在派生类中进行重写。其次,父类指针或引用必须指向派生类对象,以便在运行时确定实际调用的方法。此外,多态的实现还需要注意访问修饰符、纯虚函数和抽象基类等概念的使用。
C++多态是一种重要的面向对象编程技术,它可以提高程序的灵活性和可维护性,同时减少代码的重复性。通过继承、重写和虚函数等机制,我们可以实现多态,从而让程序更加灵活、可扩展和易于维护。
2 C++多态的类型
C++中的多态性有多种不同的类型,主要包括以下几种:
编译时多态性:这种多态性是通过函数重载和运算符重载来实现的。它允许我们使用相同的函数名或操作符来定义多个版本,这些版本在编译时会根据其参数类型和个数进行选择。
运行时多态性:这种多态性是通过虚函数和基类指针或引用来实现的。它允许我们使用基类指针或引用指向子类对象,并调用子类重写后的虚函数。这种多态性也称为动态绑定或延迟绑定。
构造函数多态性:这种多态性是通过在派生类中重载基类构造函数来实现的。它允许我们在创建派生类对象时,可以调用基类的构造函数,并在其中添加派生类的初始化代码。
类型多态性:这种多态性是通过在基类中使用指针或引用调用派生类对象来实现的。它允许我们使用基类指针或引用调用派生类的方法,这些方法可以在运行时动态地绑定到正确的对象上。
泛型编程多态性:这种多态性是通过模板和泛型编程来实现的。它允许我们编写可适用于不同数据类型的代码,这些代码在编译时会根据实际数据类型进行选择。
这些多态性类型提供了不同的编程方式和工具,使我们能够更灵活地设计和实现程序。
3 虚函数实现多态案例分析
该案例的代码是基于C++多态上提供的案例去做的分析
3.1 非虚函数成员函数调用的案例
3.1.1 测试代码
需要注意的地方是基类Shape的area成员函数是未用virtual关键字去修饰成员函数的: int area()
#include <iostream>using namespace std;class Shape {protected:int width, height;public:Shape( int a=0, int b=0){width = a;height = b;cout << "base constructor class" <<endl;}int area() ------>基类成员函数实现未用virtual关键字修饰{cout << "Parent class area :" <<endl;return 0;}~Shape(){cout << "Base DeConstructor Shape" <<endl;}
};
class Rectangle: public Shape{public:Rectangle( int a=0, int b=0):Shape(a, b) {cout << "Rectangle constructor class" <<endl;}int area (){cout << "Rectangle class area :" <<endl;return (width * height);}~Rectangle(){cout << " Rectangle class deconstructor "<<endl;}
};
class Triangle: public Shape{public:Triangle( int a=0, int b=0):Shape(a, b) {cout << "Triangle constructor class" <<endl;}int area (){cout << "Triangle class area :" <<endl;return (width * height / 2);}~Triangle(){cout << " Triangle class deconstructor "<<endl;}
};
// 程序的主函数
int main( )
{Shape *shape;cout <<" ============== 1 =============="<<endl;Rectangle rec(10,7);cout <<" ============== 2 =============="<<endl;Triangle tri(10,5);cout <<" ============== 3 =============="<<endl;// 存储矩形的地址shape = &rec;cout <<" ============== 4 =============="<<endl;// 调用矩形的求面积函数 areashape->area();cout <<" ============== 5 =============="<<endl;// 存储三角形的地址shape = &tri;cout <<" ============== 6 =============="<<endl;// 调用三角形的求面积函数 areashape->area();cout <<" ============== 7 =============="<<endl;return 0;
}
3.1.2 测试运行结果
重点关注下面的log:
============== 4 ==============
Parent class area :============== 5 ============================ 6 ==============
Parent class area :============== 7 ==============
测试运行结果:
$ g++ base_derive_test.cpp -o demo
$ ./demo ============== 1 ==============
base constructor class
Rectangle constructor class============== 2 ==============
base constructor class
Triangle constructor class============== 3 ============================ 4 ==============
Parent class area :============== 5 ============================ 6 ==============
Parent class area :============== 7 ==============Triangle class deconstructor
Base DeConstructor ShapeRectangle class deconstructor
Base DeConstructor Shape
$
3.2 虚函数成员函数调用案例
3.2.1 虚函数实现测试代码
基类Shape的area成员函数是未用virtual关键字去修饰成员函数的: virtual int area()
#include <iostream>using namespace std;class Shape {protected:int width, height;public:Shape( int a=0, int b=0){width = a;height = b;cout << "base constructor class" <<endl;}virtual int area(){cout << "Parent class area :" <<endl;return 0;}~Shape(){cout << "Base DeConstructor Shape" <<endl;}
};
class Rectangle: public Shape{public:Rectangle( int a=0, int b=0):Shape(a, b) {cout << "Rectangle constructor class" <<endl;}int area (){cout << "Rectangle class area :" <<endl;return (width * height);}~Rectangle(){cout << " Rectangle class deconstructor "<<endl;}
};
class Triangle: public Shape{public:Triangle( int a=0, int b=0):Shape(a, b) {cout << "Triangle constructor class" <<endl;}int area (){cout << "Triangle class area :" <<endl;return (width * height / 2);}~Triangle(){cout << " Triangle class deconstructor "<<endl;}
};
// 程序的主函数
int main( )
{Shape *shape;cout <<" ============== 1 =============="<<endl;Rectangle rec(10,7);cout <<" ============== 2 =============="<<endl;Triangle tri(10,5);cout <<" ============== 3 =============="<<endl;// 存储矩形的地址shape = &rec;cout <<" ============== 4 =============="<<endl;// 调用矩形的求面积函数 areashape->area();cout <<" ============== 5 =============="<<endl;// 存储三角形的地址shape = &tri;cout <<" ============== 6 =============="<<endl;// 调用三角形的求面积函数 areashape->area();cout <<" ============== 7 =============="<<endl;return 0;
}
3.2.2 测试运行结果
调用成员函数erea时的结果如下所示:
============== 4 ==============
Rectangle class area :============== 5 ============================ 6 ==============
Triangle class area :============== 7 ==============
整个测试程序的运行结果:
$ g++ base_derive_test.cpp -o demo
$ ./demo ============== 1 ==============
base constructor class
Rectangle constructor class============== 2 ==============
base constructor class
Triangle constructor class============== 3 ============================ 4 ==============
Rectangle class area :============== 5 ============================ 6 ==============
Triangle class area :============== 7 ==============Triangle class deconstructor
Base DeConstructor ShapeRectangle class deconstructor
Base DeConstructor Shape
$
3.3 基类析构函数的实现
基类的析构函数在实现定义的时候建议采用虚函数定义的方式去声明和实现:
3.3.1 析构函数定义和实现案例
class Shape {protected:int width, height;public:Shape( int a=0, int b=0){width = a;height = b;cout << "base constructor class" <<endl;}virtual int area(){cout << "Parent class area :" <<endl;return 0;}virtual ~Shape(){cout << "Base DeConstructor Shape" <<endl;}
};
3.3.2 基类析构函数采用虚函数实现的原因
基类析构函数采用虚函数实现主要是为了确保正确的资源清理和避免潜在的内存泄漏问题。
当使用基类指针或引用指向派生类对象时,如果析构函数不是虚函数,那么只有基类的析构函数会被调用,而派生类的析构函数不会被调用。这样会导致派生类对象中的资源无法被正确地清理,从而产生内存泄漏或其他资源泄漏问题。
如果将基类的析构函数声明为虚函数,那么在通过基类指针或引用删除一个派生类对象时,派生类的析构函数也会被正确调用。这样可以确保派生类对象中的资源被正确清理,避免内存泄漏和其他资源泄漏问题。
另外,析构函数采用虚函数实现还可以确保在派生类析构函数执行之前,基类的析构函数已经执行完毕。这样可以保证正确的析构顺序,避免因析构顺序不当而导致的问题。
因此,为了避免潜在的资源清理问题和保证正确的析构顺序,通常将基类的析构函数声明为虚函数。
3.4 纯虚函数
在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是您在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。
纯虚函数的定义格式为:virtual int area() = 0;
= 0
告诉编译器,函数没有主体,上面的虚函数是纯虚函数。
基类中定义了纯虚函数,则该基类被成为虚基类,对应的纯虚函数必须要在派生类中去实现。
相关文章:
C++多态的理解
C多态的理解 1 C多态的概念2 C多态的类型3 虚函数实现多态案例分析3.1 非虚函数成员函数调用的案例3.1.1 测试代码3.1.2 测试运行结果 3.2 虚函数成员函数调用案例3.2.1 虚函数实现测试代码3.2.2 测试运行结果 3.3 基类析构函数的实现3.3.1 析构函数定义和实现案例3.3.2 基类析…...
关于深拷贝和浅拷贝你需要了解的内容
深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是在复制对象或数据结构时使用的两种不同的策略,它们的主要区别在于复制后新旧对象之间的关系以及对嵌套对象的处理方式。 浅拷贝: 浅拷贝创建一个新对象ÿ…...

Visual Studio自定义模板参数、备注
模板路径: VS2022 x64:C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\ItemTemplatesVS2022 x86:C:\Program Files (x86)\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\ItemTemplates 一、声明和启用模板…...

机器学习-数值特征
离散值处理 import pandas as pd import numpy as npvg_df pd.read_csv(datasets/vgsales.csv, encoding "ISO-8859-1") vg_df[[Name, Platform, Year, Genre, Publisher]].iloc[1:7]NamePlatformYearGenrePublisher1Super Mario Bros.NES1985.0PlatformNintendo2…...

Rocky(centos)安装nginx并设置开机自启
一、安装nginx 1、安装依赖 yum install -y gcc-c pcre pcre-devel zlib zlib-devel openssl openssl-devel 2、去官网下载最新的稳定版nginx nginx: downloadhttp://nginx.org/en/download.html 3、将下载后的nginx上传至/usr/local下 或者执行 #2023-10-8更新 cd /usr/…...
Android约束布局ConstraintLayout的Guideline,CardView
Android约束布局ConstraintLayout的Guideline,CardView <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:a…...
LVGL8.3.6 Flex(弹性布局)
使用lv_obj_set_flex_flow(obj, flex_flow)函数 横向拖动 LV_FLEX_FLOW_ROW 将子元素排成一排而不包裹 LV_FLEX_FLOW_ROW_WRAP 将孩子排成一排并包裹起来 LV_FLEX_FLOW_ROW_REVERSE 将子元素排成一行而不换行,但顺序相反 LV_FLEX_FLOW_ROW_WRAP_REVERSE 将子元素…...

计算机算法分析与设计(8)---图像压缩动态规划算法(含C++)代码
文章目录 一、知识概述1.1 问题描述1.2 算法思想1.3 算法设计1.4 例题分析 二、代码 一、知识概述 1.1 问题描述 1. 一幅图像的由很多个像素点构成,像素点越多分辨率越高,像素的灰度值范围为0~255,也就是需要8bit来存储一个像素的灰度值信息…...

React 状态管理 - Mobx 入门(上)
Mobx是另一款优秀的状态管理方案 【让我们未来多一种状态管理选型】 响应式状态管理工具 扩展学习资料 名称 链接 备注 mobx 文档 1. MobX 介绍 MobX 中文文档 mobx https://medium.com/Zwenza/how-to-persist-your-mobx-state-4b48b3834a41 英文 Mobx核心概念 M…...

OLED透明屏技术在智能手机、汽车和广告领域的市场前景
OLED透明屏技术作为一种新型的显示技术,具有高透明度、触摸和手势交互、高画质和图像显示效果等优势,引起了广泛的关注。 随着智能手机、汽车和广告等行业的快速发展,OLED透明屏技术也在这些领域得到了广泛的应用。 本文将介绍OLED透明屏技…...

考研是为了逃避找工作的压力吗?
如果逃避眼前的现实, 越是逃就越是会陷入痛苦的境地,要有面对问题的勇气,渡过这个困境的话,应该就能一点点地解决问题。 众所周知,考研初试在大四上学期的十二月份,通常最晚的开始准备时间是大三暑假&…...

广州华锐互动:VR动物解剖实验室带来哪些便利?
随着科技的不断发展,我们的教育方式也在逐步变化和进步。其中,虚拟现实(VR)技术的应用为我们提供了一种全新的学习方式。尤其是在动物解剖实验中,VR技术不仅能够增强学习的趣味性,还能够提高学习效率和准确性。 由广州华锐互动开发…...

Uniapp 婚庆服务全套模板前端
包含 首页、社区、关于、我的、预约、订购、选购、话题、主题、收货地址、购物车、系统通知、会员卡、优惠券、积分、储值金、订单信息、积分、充值、礼品、首饰等 请观看 图片参观 开源,下载即可 链接:婚庆服务全套模板前端 - DCloud 插件市场 问题反…...

RabbitMQ-网页使用消息队列
1.使用消息队列 几种模式 从最简单的开始 添加完新的虚拟机可以看到,当前admin用户的主机访问权限中新增的刚添加的环境 1.1查看交换机 交换机列表中自动新增了刚创建好的虚拟主机相关的预设交换机。一共7个。前面两个 direct类型的交换机,一个是…...

弹性资源组件elastic-resource设计(四)-任务管理器和资源消费者规范
简介 弹性资源组件提供动态资源能力,是分布式系统关键基础设施,分布式datax,分布式索引,事件引擎都需要集群和资源的弹性资源能力,提高伸缩性和作业处理能力。 本文介绍弹性资源组件的设计,包括架构设计和详…...

【Java】微服务——RabbitMQ消息队列(SpringAMQP实现五种消息模型)
目录 1.初识MQ1.1.同步和异步通讯1.1.1.同步通讯1.1.2.异步通讯 1.2.技术对比: 2.快速入门2.1.RabbitMQ消息模型2.4.1.publisher实现2.4.2.consumer实现 2.5.总结 3.SpringAMQP3.1.Basic Queue 简单队列模型3.1.1.消息发送3.1.2.消息接收3.1.3.测试 3.2.WorkQueue3.…...
react高阶成分(HOC)实践例子
以下是一个使用React函数式组件的高阶组件示例,它用于添加身份验证功能: import React, { useState, useEffect } from react;// 定义一个高阶组件,它接受一个组件作为输入,并返回一个新的包装组件 const withAuthentication (W…...

20231005使用ffmpeg旋转MP4视频
20231005使用ffmpeg旋转MP4视频 2023/10/5 12:21 百度搜搜:ffmpeg 旋转90度 https://zhuanlan.zhihu.com/p/637790915 【FFmpeg实战】FFMPEG常用命令行 https://blog.csdn.net/weixin_37515325/article/details/127817057 FFMPEG常用命令行 5.视频旋转 顺时针旋转…...

MySQL-锁
MySQL的锁机制 1.共享锁(Shared Lock)和排他锁(Exclusive Lock) 事务不能同时具有行共享锁和排他锁,如果事务想要获取排他锁,前提是行没有共享锁和排他锁。而共享锁,只要行没有排他锁都能获取到。 手动开启共享锁/排他锁: -- 对…...
ES6中变量解构赋值
数组的解构赋值 ES6规定以一定模式从数组、对象中提取值,然后给变量赋值叫做解构。 本质上就是一种匹配模式,等号两边模式相同,左边的变量就能对应的值。 假如解构不成功会赋值为undefined。 不需要匹配的位置可以置空 let [ a, b, c] …...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

Xcode 16 集成 cocoapods 报错
基于 Xcode 16 新建工程项目,集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...