简述虚函数表

article/2025/10/4 5:07:18

前段时间我在博客中简单地说了下C++的虚函数,所谓虚函数,就是C++实现多态性的方法。那么编译器是如何识别虚函数的呢?据百度百科描述,C++并未规定用何种方法实现虚函数,但是大部分编译器厂商都选择使用虚函数表这种方法,那到底什么是虚函数表???

 

虚函数表,称为V-Table。虚函数表是一片连续的内存区域,每个内存单元存放着JMP指令地址。

看到这里,可能会比较懵逼,啥是内存单元,啥是JMP指令?我们先插一段汇编语言的内容,帮助更好的理解虚函数表。


备用知识:

  • 每个内存单元都有自己的内存地址,内存单元存放数据。
  • 每个内存单元存放一个字节的数据,为8位。对于不同的机器,一个字为不同的长度,但都是字节的整数倍。如8086的机器为16位,其字长为2字节。一个字长为计算机的一个处理单元。
  • JMP指令:无条件跳转。类似于高级语言中的goto语句。

虚函数工作原理:

C++中规定了虚函数的行为,即虚函数是干什么的,但是并未规定虚函数应该怎么实现。因此这是编译器需要解决的问题。通常来说,编译器会利用虚函数表(V-Table)解决虚函数的问题。

虚函数表实际上是一个数组,其中存储了为类对象进行声明的虚函数的地址。

懵逼。。这里有许多问题需要解决:

  1. 既然虚函数的地址存放在V-Table中,那么V-Table的地址从哪找?
  2. V-Table有多少?是一个V-Table存放着所有的虚函数地址,还是一个V-Table存放一定数量的地址?
  3. 具体的过程是如何的?

我们一个一个解答:

  1. 我们在声明了一个虚函数类的对象的同时,这个对象被添加了一个隐式成员。该成员保存了指向虚函数地址数组的指针。

       函数地址数组:函数是有地址的,将函数的地址存放在一个数组中,就是函数地址数组或函数指针数组。

       这个成员对象保存的就是这个数组的指针,而该数组就是虚函数表(V-Table)。(不知道这样说清不清楚。)

    2.  只要包含虚函数的类就会有一个虚函数表,当这个类是基类时,它的派生类也会有相应的虚函数表。当一个类有多个对象的时候,这些对象共享一个虚函数表。

        例如:基类对象包含一个指针,该指针指向基类中所有虚函数的地址表,派生类将包含一个指向独立地址表的指针。两个表是相互独立的!当派生类重新实现了基类中的虚函数,那么派生类的虚函数表将保存新的函数地址。如果派生类并未对虚函数做改动,那么虚函数表将保存原始函数地址。也就是说,派生类的虚函数表进行改动并不会对基类的虚函数表有影响。

    3. 具体过程:先看一段伪代码

class Pets{
privateString type;String name;
public:virtual void show_name(); virtual void show_type();
};class Dogs: public Pets{
private:int age;String ownerName;
public:void show_name(){}virtual void show_age();
};

这段代码描述宠物基类和继承宠物基类的狗类。

int main(){Dogs dog("mammal","Bob",2,"Peter");Pets *pets = &dog;pets->show_name();return 0;
}

当执行pets->show_name()时,会经历以下过程:

  1. 通过pets找到隐藏成员的地址,并通过地址的值找到改数据表示的虚函数表;
  2. 获取表中内容为地址7800的地址(就是找到调用的函数)
  3. 前往地址7800,并执行函数。

 


总结:

虚函数的一种使用是通过虚函数表实现的,所以不可避免的在内存与速度方面都会有影响:

  1. 每个对象的大小都会增大一个存储地址的空间,用来存放隐藏成员代表指向的地址。
  2. 对于每个含有虚函数的类,编译器都会创建一个虚函数表;
  3. 每次调用虚函数,都需要经历一次寻址过程,到虚函数表中寻找虚函数地址,耗费了时间。

关于虚函数使用总结:

  1. 构造函数不能是虚函数。当初始化派生类对象的时候,将调用派生类的构造函数,之后派生类的构造函数又会调用基类中的构造函数,这种顺序不同于继承机制,所以派生类不能继承基类的构造函数,因此将构造函数声明称虚函数没有用。
  2. 析构函数应该声明为虚函数。前文讲过,不再赘述。
  3. 友元不能是虚函数,因为虚函数必须是成员函数,而友元不是成员类。但是友元函数可以使用虚函数。

虚函数概念及使用

C++纯虚函数

虚析构函数与纯虚析构函数

 

参考文献:

《C++ Primer Plus》


http://chatgpt.dhexx.cn/article/6DZVQnFa.shtml

相关文章

虚函数表的问题

虚函数表: 多态是由虚函数实现的,而虚函数主要是通过虚函数表(V-Table)来实现的。 如果一个类中包含虚函数(virtual修饰的函数),那么这个类就会包含一张虚函数表,虚函数表存储的每…

虚函数表详解及其应用场景

目录 概述1. 虚函数表概述2. 虚函数表的实现原理2.1. 虚函数的声明和定义2.2. 虚函数表的创建和初始化2.3. 虚函数调用的过程 3. 虚函数表的应用场景3.1. 多态性3.2. 基类指针和引用的使用3.3. 动态绑定3.4. 接口定义 结论 概述 在面向对象编程中,虚函数表&#xf…

C++ 面试必问:深入理解虚函数表

点击蓝字 关注我们 深入理解C 虚函数表 C中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。 Derive d; Base1 *b1 &d; Base2 *b2 &d; Base3 *b3 …

C++ 虚函数表

C类在内存中的存储方式 C 内存分为 5 个区域: 堆 heap :由 new 分配的内存块,其释放编译器不去管,由程序员自己控制。如果程序员没有释放掉,在程序结束时系统会自动回收。涉及的问题:“缓冲区溢出”、“内…

ThinkPHP3.2.2获取数据列getField()优化

getField()是一个常用方法,我习惯用来获取带key的数组,方便数据整合。 使用第1个参数,传入一个字段名,获取某一个数据值,返回满足条件的数据表中的该字段的第一行的值: $id M("User")->getFi…

java class getfield_java.lang.Class.getField()方法实例

全屏 java.lang.Class.getField() 返回一个Field对象,它反映此Class对象所表示的类或接口的指定公共成员字段。 name参数是一个字符串,指定所需字段的简单名称。 声明 以下是java.lang.Class.getField()方法的声明public Field getField(String name) th…

java getfield_Java 反射:通过 getField() 设置公共全局变量

Java 通过 getField() 操作公共全局变量 以前写 JavaWeb 项目启动初始化系统配置全局变量的代码,都是 variable Properties.getProperty(name) 这样一行一行代码的设置,变量少还好说,变量一多真的很磨叽。所以一直想通过 循环 简化代码&…

getField和getDeclaredField的区别

这两个方法都是用于获取字段 1.getField 只能获取public的,包括从父类继承来的字段。 2.getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。 (注: 这里只能获取到private的字段,但并不…

vscode插件开发总结

一、关于vscode插件 相信大家对vscode应该都不陌生,VSCode是微软出的一款轻量级代码编辑器,免费而且功能强大,以功能强大、提示友好、不错的性能和颜值俘获了大量开发者的青睐,对JavaScript和NodeJS的支持非常好,自带…

2021-前端-VsCode插件

此乃吾习前端,VsCode之插件,个人所装,喜着自拿,不足之处还望海涵,多加批评。 1.Auto Close Tag——自动闭合尾部的标签 2.Atuo Rename Tag——修改 html 标签 自动帮你完成头部和尾部闭合标签的同步修改 3.Bracket…

关于VSCode插件的安装位置

VSCode的插件地址修改_上善若泪-CSDN博客_vscode插件位置文章目录1 data文件夹2 使用--extensions-dir命令3 使用mklink命令vscode编辑器强大的地方是可以使用各种各样的插件,但是插件默认的地方是在:C盘,让一些强迫症可能会受不了,非要迁移到…

vscode 插件-常用插件

VSCode常用插件(安装步骤同汉化) 1、*Auto Close Tag (自动闭合HTML/XML标签) 2、*Auto Rename Tag (自动帮你完成尾部闭合标签的同步修改,不过有些bug) 3、*Prettier(Prettier 是目前 Web 开发中最受欢迎的代码格式化程序) 安装Prettier -Code formatter这个插件…

Vscode 插件包下载并离线安装

打开VSCode插件官网 官网链接是https://marketplace.visualstudio.com/vscode 搜索Go 在输入框中输入go,搜索,结果如下: 点击Download Extension下载 注意:有时候找不到Download Extension,可能是网速加载慢&…

VsCode插件安装及推荐

1、快捷键Ctrl P,打开插件,输入 ext install (我习惯的输入方式); 2、或者点击图片中的圈红的按钮,也可以进入插件安装商城; 3、下面开始说下我目前安装的插件(我目前是vue开发&…

VScode安装离线插件

1. 下载及安装 首先在VScode官方插件库下载自己所需要的插件:https://marketplace.visualstudio.com/vscode 下载成功之后是以**.vsix**结尾的文件 然后再VScode软件中进行导入刚下载的文件 如果提示蓝色信息则为安装成功,红色则为失败 2. 版本不兼容报…

VSCode前端必备插件

跨平台的文本编辑器。由于其卓越的性能和丰富的功能,它很快就受到了大家的喜爱。 就像大多数 IDE 一样,VSCode 也有一个扩展和主题市场,包含了数以千计质量不同的插件。为了帮助大家挑选出值得下载的插件,我们针对性的收集了一些…

如何写一个vscode插件

1.运行yo code创建项目 2.选择使用yarn或者npm 3.运行 官网这个例子需要我们 ctrl shirt p 调出输入框, 然后在里面输入hello w 就可以如图所示 activationEvents: 当什么情况下, 去激活这个插件 activationEvents.onCommand: 在某个命令下激活(之后会专门列出很多其他条件…

Python好用的VSCode插件

1. Better Comments 这是一个让你能更好地编写注释的工具,它能根据关键词用不同的颜色高亮代码片段。支持以下类型的高亮: 感叹号 “!” 代码警告。问号“?”代表存留疑问。TODO 代码未来将要进行的操作。param 参数 2. autoDocstring 能够自动生成函…

VScode插件(自用)

一、Material Icon Theme 图标插件 它采用了 Google Material Design 风格,文件图标以及文件夹图标覆盖非常的全面。 二、 颜色主题插件Themes(代码颜色)中的 Monokai Dimmed 三、css peek 使用此插件,你可以追踪至样式表中 CSS…

2022年好用的Vscode插件

Chinese(VSCode汉化插件) 第一款推荐的插件叫Chinese 是一款VSCode汉化插件 这样,VSCode就完成了汉化 Material Theme(主题插件) 第二款插件是一个好看的主题插件Material Theme 它包含了多套不同色彩风格的主题,以及好看的图标样式。 选择不同主题可以…