C++中,虚函数的作用详解

news2024/9/22 1:40:33

我个人认为虚函数的作用有两个:

增加安全性;提醒子类去做该做的事情。

提高效率;不是指程序执行效率,而是编码效率。

首先我这里要纠正一下:

一个函数被定义为虚函数,不代表这个函数未被实现;

定义函数为虚函数,表示允许基类使用指针去调用子类实现的这个函数;

当你将函数定义为纯虚函数时,才表示函数未被实现。

纯虚函数相当于一个接口,主要作用是为了规范,程序员必须实现这个继承类的函数。

接下来我们看一个虚函数的经典应用,搞清楚这个例子,你对虚函数会有一个新的认识。

虚函数的虚就虚在“运行时”编译,而C++中的另一个模版是在“编译时”编译,这两者的概念是不同的。

即父类调用子类的函数不是在编译时确定,而是在程序运行时确定。

虚函数要达到多态的效果,只能借助指针或引用。

虚函数的底层实现

虚函数是如何做到因对象的不同而调用其相应的函数的呢?现在我们就来剖析虚函数。我们先定义两个类

实现原理:虚函数表+虚表指针

关键字:虚函数底层实现机制;虚函数表;虚表指针

编译器处理虚函数的方法是:为每个类对象添加一个隐藏成员,隐藏成员中保存了一个指向函数地址数组的指针,称为虚表指针(vptr),这种数组成为虚函数表(virtual function table, vtbl),即,每个类使用一个虚函数表,每个类对象用一个虚表指针。

举个例子:基类对象包含一个虚表指针,指向基类中所有虚函数的地址表。派生类对象也将包含一个虚表指针,指向派生类虚函数表。看下面两种情况:

如果派生类重写了基类的虚方法,该派生类虚函数表将保存重写的虚函数的地址,而不是基类的虚函数地址。

如果基类中的虚方法没有在派生类中重写,那么派生类将继承基类中的虚方法,而且派生类中虚函数表将保存基类中未被重写的虚函数的地址。注意,如果派生类中定义了新的虚方法,则该虚函数的地址也将被添加到派生类虚函数表中。

下面的图片体现了上述的底层实现机制:

调用虚函数时,程序将查看存储在对象中的虚函数表地址,转向相应的虚函数表,使用类声明中定义的第几个虚函数,程序就使用数组的第几个函数地址,并执行该函数。

使用虚函数后的变化

对象将增加一个存储地址的空间(32位系统为4字节,64位为8字节)。

每个类编译器都创建一个虚函数地址表。

对每个函数调用都需要增加在表中查找地址的操作。

纯虚函数

纯虚函数是声明在基类中,没有定义,继承的子类都必须实现该方法。将一个函数声明为纯虚函数,只需在该函数后加一个“=0”。

virtual int Test()=0;

为何要引入纯虚函数?

其一,是为了实现多态机制;

其二,在很多场景下,基类生成的对象都不符合要求,只能通过子类去实现。基类通过指针调用子类函数,类似于泛型,使用不变的代码实现可变的算法。

为了解决上述两个问题,C++引入了纯虚函数,将函数定义为纯虚函数,编译器要求派生类必须重写纯虚函数,以到达实现多态的目的。

纯虚函数所在的类我们称为抽象类,不能生成对象。不能创建抽象类的实例,只能创建子类的实例。

纯虚函数的目的是为了让子类继承函数的接口。

纯虚函数的意义是让所有子类都能够执行纯虚函数的动作,但是基类无法为纯虚函数提供一个缺省的实现。通俗来讲,声明纯虚函数是为了告诉子类,你必须要实现纯虚函数,至于怎么实现纯虚函数,这是你的事情。

抽象类

上面提到纯虚函数所在的类为抽象类,抽象类是一种特殊的类,多用于抽象和设计,通常处于继承结构的上层。例如,在设计模式中,你应该经常会看到抽象类。

作用

将相关的操作作为接口放在基类中,为子类提供一个公共的模版,子类将具体实现基类中的接口操作。

注意

抽象类不能用作于定义对象;

抽象类只能用作于基类,不能作用于子类,纯虚函数的实现由子类完成。如果子类中只是继承了纯虚函数,未对纯虚函数进行定义,该类仍然为抽象类。如果子类实现了基类中的纯虚函数,该类是可以建立具体对象的类,就不在是抽象类。

总结

(1) 基类方法中声明了方法为虚后,该方法在基类派生类中是虚的。

(2) 若使用指向对象的引用或指针调用虚方法,程序将根据对象类型来调用方法,而不是指针的类型。

(3)如果定义的类被用作基类,则应将那些要在派生类中重新定义的类方法声明为虚。

构造函数不能为虚函数。

基类的析构函数应该为虚函数。

友元函数不能为虚,因为友元函数不是类成员,只有类成员才能是虚函数。

如果派生类没有重定义函数,则会使用基类版本。

重新定义继承的方法若和基类的方法不同(协变除外),会将基类方法隐藏;如果基类声明方法被重载,则派生类也需要对重载的方法重新定义,否则调用的还是基类的方法。

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

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

相关文章

leetcode.nvim使用cookie无法登陆问题

错误描述: 使用力扣 (LeetCode) 全球极客挚爱的技术成长平台 的cookie在neovim上使用leetcode.nvim进行登录会出现curl xxx -D xxxx的报错。 解决方法: 使用LeetCode - The Worlds Leading Online Programming Learning Platform这个网站的cookie进行登…

这7款高效爬虫工具软件,非常实用!

在当今数据驱动的时代,自动化爬虫工具和软件成为了许多企业和个人获取数据的重要手段。这里会介绍6款功能强大、操作简便的自动化爬虫工具,用好了可以更高效地进行数据采集。 1. 八爪鱼采集器 八爪鱼是一款功能强大的桌面端爬虫软件,主打可…

轮船控制系统nmea2000电缆组件 7/8 T型连接器

NMEA 2000 7/8 T型连接器概述 NMEA 2000 7/8 T型连接器是专为船舶控制系统设计的电缆组件,主要用于连接船上的各种电子设备和系统,如GPS接收器、自动驾驶仪、风速和风向传感器、深度声纳等。这些设备通过NMEA 2000总线共享数据,包括导航信息…

1.Fabric框架

要了解Fabric,首先要知道Hyperledger开源项目。 2015年12月,由开源世界的旗舰组织Linux基金会牵头,30家初始企业成员共同宣布Hyperledger联合项目成立。Hyperledger 超级账本,是首个面向企业应用场景的分布式账本平台&#xff0c…

【算法】深入理解并优化算法:提升软件开发效率与质量

目录 一、算法的基本概念 输入 输出 确定性 有限性 有效性 二、常见算法类型 1. 排序算法 选择排序(Selection Sort) 插入排序(Insertion Sort) 快速排序(Quick Sort) 归并排序(Mer…

搜维尔科技:Movella推出面向自主机器和边缘人工智能应用的Xsens MTi传感器组合

Movella近日宣布针对自主机器和边缘人工智能应用,已增强旗下的Xsens MTi™惯性传感器模块。Xsens MTi传感器可与NVIDIA Jetson™平台轻松集成,用于边缘人工智能和机器人技术,并与NVIDIA Jetson AGX Orin™、NVIDIA Jetson Orin™ NX和NVIDIA …

基本聚集函数和case的应用

文章目录 1.基本聚集函数(1)基本聚集函数的介绍(2)使用基本聚集函数的简单例子&#xff08;1&#xff09;查询最大年龄&#xff0c;最小年龄年龄和平均年龄<1>最大年龄<2>最小年龄<3>平均年龄 (2&#xff09;配合上where语句&#xff0c;查询女士的平均年龄(…

虚拟化环境中如何实现以业务为中心的网络隔离?Everoute 推出虚拟专有云网络(VPC)功能

目前&#xff0c;不少企业都利用云计算和虚拟化技术提升 IT 系统灵活性、敏捷性和成本效益。然而&#xff0c;云环境的“多租户”特性也为业务安全带来了新的挑战&#xff0c;如何保障不同业务主体或租户之间的数据安全和网络隔离&#xff0c;成为企业关注的焦点。 作为 Smart…

(C++) 智能指针指定删除器

文章目录 ⌚前言⏲️注意 ⌚unique_ptr⏲️说明⏲️实例 ⌚shared_ptr⏲️说明⏲️实例 ⌚拓展⏲️函数类型 & 函数指针类型 ⌚END&#x1f31f;关注我 ⌚前言 自C11后&#xff0c;推出了三个智能指针。其中 unique_ptr和shared_ptr可以指定删除器。 但两者的形式却不太一…

【Canvas与艺术】红底白色压边五角星

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>精确压边五角星版本2</title><style type"text/css&qu…

Java IO模型深入解析:BIO、NIO与AIO

Java IO模型深入解析&#xff1a;BIO、NIO与AIO 一. 前言 在Java编程中&#xff0c;IO&#xff08;Input/Output&#xff09;操作是不可或缺的一部分&#xff0c;它涉及到文件读写、网络通信等方面。Java提供了多种类和API来支持这些操作。本文将从IO的基础知识讲起&#xff…

虚拟现实和增强现实技术系列—Expressive Talking Avatars

文章目录 1. 概述2. 背景介绍3. 数据集3.1 设计标准3.2 数据采集 4. 方法4.1 概述4.2 架构4.3 目标函数 5. 实验评测5.1 用户研究5.2 我们方法的结果5.3 比较与消融研究 1. 概述 支持远程协作者之间的交互和沟通。然而&#xff0c;明确的表达是出了名的难以创建&#xff0c;主…

两台电脑之间如何进行数据传输?两台电脑数据传输攻略

在数字化时代&#xff0c;电脑之间的数据传输变得日益重要。无论是个人用户还是企业用户&#xff0c;经常需要在不同的电脑之间共享或迁移数据。那么&#xff0c;两台电脑之间如何进行数据传输呢&#xff1f;本文将详细介绍两台电脑之间进行数据传输的几种常见方法&#xff0c;…

奖金+奖杯+荣誉证书 | FPGA硬件扑克牌比赛邀你参加

关键词&#xff1a;个人赛&#xff0c;随机发牌&#xff0c;比运气&#xff0c;还比设计&#xff0c;好玩又有趣 想用FPGA玩一场有趣的游戏吗&#xff1f;想检验自己的FPGA算法水平吗&#xff1f; “向日葵杯”全国教育仿真技术大赛——FPGA硬件扑克牌对抗赛等你来体验&#…

I can‘t link the chatbot model with react

题意&#xff1a;我无法将聊天机器人模型 chatbot 与React连接起来 问题背景&#xff1a; This is the model from flask import Flask, request, jsonify from flask_cors import CORS import json import nltk import numpy as np import random import pickle from time i…

英特尔终于宣布了解决CPU崩溃和不稳定性问题的方法,声称过高的电压是根本原因;补丁预计将于8月中旬推出【更新】

英特尔终于宣布了解决CPU崩溃和不稳定性问题的方法&#xff0c;声称过高的电压是根本原因&#xff1b;补丁预计将于8月中旬推出【更新】 英特尔官方宣布&#xff0c;已找到困扰其CPU的崩溃问题的根本原因&#xff0c;并将于8月中旬前发布微码更新以解决这一问题&#xff0c;从而…

聊聊 C# 中的顶级语句

前言 在 C# 9.0 版本之前&#xff0c;即使只编写一行输出 “Hello world” 的 C# 代码&#xff0c;也需要创建一个 C# 类&#xff0c;并且需要为这个 C# 类添加 Main 方法&#xff0c;才能在 Main 方法中编写代码。从 C# 9.0 开始&#xff0c;C# 增加了 “顶级语句” 语法&…

获取对象碎片情况

查看oracle数据库表上碎片 先创建个函数 FUNCTION get_space_usage1(owner IN VARCHAR2,object_name IN VARCHAR2,segment_type IN VARCHAR2,partition_name IN VARCHAR2 DEFAULT NULL) RETURN sys.DBMS_DEBUG_VC2COLL PIPELINEDASufbl NUMBER;ufby NUMBER;fs1bl NUMBER…

赋值运算符重载和运算符重载

1.运算符重载 在C中&#xff0c;运算符重载是一种强大的特性&#xff0c;它允许我们为已有的运算符赋予新的意义&#xff0c;以便它们能够应用于自定义类型上。 这一特性极大地增强了C的表达能力&#xff0c;使得自定义类型的使用更加直观和自然。例如&#xff0c;如果我们定义…

【区块链+绿色低碳】包头林草市域碳中和体系建设项目 | FISCO BCOS应用案例

在双碳体系建设背景下&#xff0c;政府、企业都在积极探索碳中和价值实现路径。但是在林业碳汇场景中&#xff0c;存在着林权认证、 身份授权、多方机构协作、数据交换等流程&#xff0c;在这些复杂的业务协作中存在一些风险&#xff0c;如&#xff1a;身份信息泄漏、数据造假、…