C++基础#17:C++中的虚函数表

虚函数表(图文详解) 本文讲解了虚函数表以及继承和多态常见的面试问题 阅读详情

虚函数表简介:

前面文章学习了C++的虚函数(Virtual Function),纯虚函数等内容。那么,在多态情形下,虚函数是如何知道需要调用哪一个子类的函数呢? 答案就是虚函数表。

在C++中,虚函数被通过一张虚函数表(Virtual Table)来实现的,简称为V-Table,表中每一项是一个虚函数的地址, 也就是说,虚函数表的每一项是一个虚函数的指针。在这个表中,描述了一个类的虚函数的地址表,这张表解决了继承、覆盖(override)的问题,保证其能真实的反应实际的函数。这样,在有虚函数的类的实例中这张表被分配在了这个实例的内存中,所以当我们用父类的指针操作一个子类的时候,这张虚函数表就显得尤为重要了,它为我们指明了实际所应该调用的函数。

虚函数表中只存有一个虚函数的指针地址,不存放普通函数或是构造函数的指针地址。只要有虚函数,C++类都会存在这样的一张虚函数表。没有虚函数的C++类,是不会有虚函数表的。

简单来进行一个总结:

1)虚函数表的作用:确保能够找到真正要调用的子类的函数。

2)虚函数表创建的时间:在一个类构造的时候,创建这张虚函数表,而这个虚函数表是供整个类所共有的。虚函数表存储在对象最开始的位置。

3)虚函数表的本质:虚函数表其实就是函数指针的地址。函数调用的时候,通过函数指针所指向的函数来调用函数。

虚函数表举例:

代码(vtable5.cpp):

#include <iostream>

using namespace std;

class Base {
public:
    int a;
    virtual void fun1() {cout<<"Base::fun1"<<endl;}
    virtual void fun2() {cout<<"Base::fun2"<<endl;}
    virtual void fun3() {cout<<"Base::fun3"<<endl;}
};

class Derive : public Base{
public:
    void fun2() {cout<<"Derive::fun2"<<endl;}
};

//可以稍后再看
int main () {
    cout<<"size of Base: "<<sizeof(Base)<<endl;

    typedef void(*Func)(void);
    Base b;
    Base *d = new Derive();
    d->a = 5;
    cout<<"d->a="<<d->a<<endl<<endl;

    long* pvptr = (long*)d;
    long* vptr = (long*)*pvptr;
    Func f1 = (Func)vptr[0];
    Func f2 = (Func)vptr[1];
    Func f3 = (Func)vptr[2];

    f1();
    f2();
    f3();

    return 0;
}

运行结果:

aibook@aibookdeMacBook-Pro c_stu % g++ vtable5.cpp

aibook@aibookdeMacBook-Pro c_stu % ./a.out

size of Base: 16

size of int: 4

d->a=5

Base::fun1

Derive::fun2   //说明:调用的是子类的fun2

Base::fun3

每个类都有一个虚函数表,所以,对应的虚函数表如下:

Base中虚函数表结构:

 Derive中虚函数表结构:


说明:

1)d对象的首地址就是vptr指针的地址-pvptr;
2)取pvptr的值就是vptr-虚函数表的地址;
3)取vptr中[0][1][2]的值就是这三个函数的地址;

4)虚函数本质上是一个函数指针,int的长度也是4,所以,sizeof(Base)的值就是:16(3个指针+1个int);

5)在Derive中,g()函数重写了父类的g(),因此,在Derive的虚函数表中,vptr指向的第二个函数就是Derive::g(),而不是父类的Base::g()。

这样,就保证了在多态情形下,准能找到真正实例化的子类的对象。


C++虚函数表原理:从多态实现到内存布局的底层机制 多态是面向对象编程的核心概念,它允许不同对象对同一消息做出不同响应,实现‘一个接口,多种实现’的设计目标。其底层原理依赖于虚函数表机制,编译器为每个包含虚函数的类生成一个虚函数表,其中存储了该类所有虚函数的地址。每个对象实例则包含一个隐藏的虚表指针,指向其所属类的虚表。当通过基类指针或引用调用虚函数时,程序在运行时通过虚表指针查找虚函数表,从而确定实际调用的函数地址,实现动态绑定。这种机制虽然引入轻微性能开销,但为大型软件系统的模块化设计和代码复用提供了基础支撑。在C++开发中,理解虚函数表有助于调试复杂多 阅读详情

相关推荐

深入浅出C++虚函数:从底层原理到实战应用

C++虚函数是实现多态的核心机制,通过虚函数表和虚指针实现动态绑定。每个包含虚函数的类都有虚函数表,对象实例包含指向该表的虚指针。虚函数不能用于内联函数、构造函数和静态成员函数。基类析构函数应声明为虚函数以确保正确资源释放。虚函数适用于插件系统、图形绘制等场景,但会带来10%-20%的性能开销和额外内存占用。理解虚函数底层原理有助于编写高效灵活的C++代码。

2501_92882546的博客 926

虚函数表指针以及虚函数表创建时机

一:虚函数表指针(vptr)创建时机 vptr跟着对象走,所以对象什么时候创建出来,vptr就什么时候创建出来,也就是运行的时候。 当程序在编译期间,编译器会为构造函数中增加为vptr赋值的代码(这是编译器的行为),当程序在运行时,遇到创建对象的代码,执行对象的构造函数,那么这个构造函数里有为这个对象的vptr赋值的语句。 二:虚函数表创建时机 虚函数表创建时机是在编译期间。编译期间编译器就为每个类确定好了对应的虚函数表里的内容。 所以在程序运行时,编译器会把虚函数表的首地址赋值给虚函数表指针,所以,这个虚

qq_38158479的博客 1万+

C++虚函数表深度解析:vtable内存布局与性能优化实战

在C++面向对象编程中,多态是实现代码复用和扩展性的核心技术,它允许通过基类接口操作派生类对象。其底层原理依赖于虚函数表(vtable)机制,每个包含虚函数的类在编译期会生成一张函数地址表,对象内部则通过虚函数表指针(vptr)与之关联,从而实现运行时的动态绑定。这种机制虽然提供了灵活性,但也带来了性能开销,主要包括间接调用导致的额外内存访问和潜在的缓存不友好问题,可能影响高频调用场景的效率。针对这些挑战,开发者可以采取多种优化策略,例如利用编译器的去虚拟化(Devirtualization)能力,或在编译

weixin_30384217的博客 307

c++ 虚函数实现原理

对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。 虚函数表指针(vptr)创建时机 vptr跟着对象走,所以对象什么时候创建出来,vptr就什么时候创建出来,也就是运行的时候。 当程序在编译期间,编译器会为构造函数中增加为vptr赋值的代码(这是编译器的行为),当程序在运行时,遇到创建对象的代码,执行对象的构造函数,那么这个构造函数里有为这个对象的vptr赋值的语句。 二:虚函数表创建时机 虚函数表创..

baidu_16370559的博客 2050

C++:Coredump-X: 虚函数表指针为0/memset

使用memset直接重置类对象实例;这种错误出现的原因就是使用C的编程习惯,编写C++的代码。在delete对象,全局对象之后,一定要设置为0,然后再次使用时,判断释放为0.释放后再使用这个对象就会出现虚函数表指针为0.这种错误,有的静态代码检查工具,可以检查出来。

mzhan017的博客 1081

CFturbo 2024保姆级教程:从流量扬程到三维叶轮,手把手搞定离心泵水力设计

本文提供CFturbo 2024离心泵水力设计的全流程实战指南,从流量扬程参数输入到三维叶轮模型导出,详细解析设计步骤与优化技巧。涵盖叶轮尺寸确定、子午面型线设计、叶片角度调整等关键环节,帮助工程师高效完成CAE辅助的离心泵水力设计,提升设计质量与效率。

weixin_42569329的博客 927

(C++对象模型):虚函数表查看工具,vptr、vtbl创建时机

虚函数表查看工具,vptr、vtbl创建时机 #include <iostream> using namespace std; //基类1 class Base1 { public: virtual void f() { cout << "base1::f()" << endl; } virtual void g() { cout << "base1::g()" << endl; } }; //基类2 class Ba

baidu_41388533的博客 773

SPSS新手教程—两步聚类之结果解读

在《详解SPSS两步聚类之参数设置》一文中,我们已经了解了两步聚类的优点、分析原理,以及参数设置的技巧。 在本节中,会对IBM SPSS Statistics聚类后的结果进行解读,其中会涉及到最终聚类的结果、聚类的质量、变量重要性、聚类特征的解读。 如图1所示,我们先来回顾下本例数据在参数设置面板中的详细设置。 图1:二阶聚类设置 一、数值结果 根据上述参数设置,得到如下的数值分析结果。 首先看到自动聚类结果,如图2所示为聚类的透视表结果,展示了不同聚类数目下的BIC、BIC变化量、BIC变

nekonekoboom的博客 3万+

C++ 虚函数表和虚函数表指针的创建时机

C++ 虚函数表和虚函数表指针的创建时机

qq_40135848的博客 1579

电赛MSP430F5529之超声波测距+OLED 显示(含主要代码)

目录 前言 一、超声波介绍 二、部分代码 三、总结 题外话: 前言 哎,又双叒叕,电赛延期了,看起来像是遥遥无期,但是肯定要考虑大局,大家就继续抓紧时间学习知识,巩固自己的知识,更进一步。好了,今天主要是继承上一篇博文(OLED显示)写的,主要是写超声波测距的(US-015) 一、超声波介绍 利用TI公司的MSP430F5529单片机+超声波模块+OLED 实现 这里主要是利用单片机定时器的捕获功能来捕获超声波高电平持续时间,再计算得到距离,最后再在OLED 屏幕上显示出来,上图

不说二话的自家人的博客 1万+

初识colmap

COLMAP是一款开源的计算机视觉软件,主要用于从一系列二维图像中进行三维重建。它全称为“COLLISION-MAPping”,是一个高度集成的Structure-from-Motion (SfM) 和 Multi-View Stereo (MVS) 管道工具,由斯坦福大学开发和维护。COLMAP的主要功能包括特征检测与匹配、增量式SfM、多视图立体匹配以及优化。它能够从无序或有序的二维照片集合中恢复出三维场景的几何结构(点云)以及每张图像对应的相机姿态。

Hhsjehejj的博客 5550

C++中的虚函数表是什么时期建立的?

虚函数表是在什么时期建立的?   最近参加阿里巴巴公司的内推,面试官问了“虚函数表是在什么时期建立的?”。因为以前对虚函数表的理解不够多,所以就根据程序构建(Build)的四个过程(预编译、编译、汇编和链接),推导出虚函数表应该是在编译期确定的,原因如下:   1)预编译器主要处理那些源代码文件中的以“#”开始的预编译指令,如“#include”、“#define”。很明显这个过程可...

4275

基于STM32F407的定时器以及定时器中断的实现

基于STM32F407的定时器以及定时器中断的实现

weixin_57941207的博客 5228

宏定义中的#,##和C++中的虚函数表问题

前几天,有个同学问我宏定义中的#和##都是什么意思啊,说实话,我也不知道,不知道怎么办,google啊!说实话,自己过去对宏定义还真没有深入了解,只会使用最简单的宏定义,自从学了C++之后,基本上都不用宏定义了,用const来直接取代了,《C++ Primer》里也强烈推荐用const来取代宏定义。 关于宏定义的具体深入介绍,我也不想多说什么,想看的,请前往这个网址,个人感觉讲得...

weixin_30384031的博客 230

ArcGIS 泛克里金插值

按照如图所示的步骤填写参数,1处选择subset features。 2:输入数据。 3:输出训练数据。 4:输出测试数据。 5:80,表示80%的比例是训练数据,20%是测试数据。 6:输入的百分比。 1:选择geostatistical wizard。 2:插值方法,克里金插值 3:训练数据。 4:数据字段。 点击下一步: 1:表示泛克里金插值。 2:输出表面类型。 3:转换类型none。 4:趋势剔除的阶数。 点击下一步: 表示东北—西南方向变化平缓。 1:模型优化 2:模型类型(stabl.

yuanYW7556的博客 7275

C++多态机制深度解析:从虚函数表到现代多态实践

多态是面向对象编程的核心概念,它允许通过统一的接口调用不同的实现,是实现代码复用和扩展性的关键技术。其原理基于动态绑定机制,在C++中主要通过虚函数表(vtable)和虚函数指针(vptr)实现,使得程序能在运行时根据对象实际类型决定调用哪个函数。这一机制极大地提升了代码的灵活性和可维护性,是设计模式如策略模式、工厂模式的基础。在图形渲染、插件系统、算法框架等场景中,多态能有效减少条件判断,支持开闭原则。本文聚焦C++多态的实现细节,深入探讨虚函数表机制、重写规范以及现代C++中如std::variant的

weixin_34245082的博客 426

微信小程序 - 解决请求报错 request:fail errcode:-201 cronet_error_code:-201 error_msg:net::ERR_CERT_DATE_INVALID

微信小程序报错“request:fail errcode:-201 cronet_error_code:-201 error_msg:net::ERR_CERT_DATE_INVALID“,微信小程序请求报错,微信小程序errcode:-201,服务器报错,无法调用接口,微信小程序真机https请求失败,微信小程序wx.request接口报错,小程序真机调试运行接口都报错了,真机测试下网络请求都不行了且报错,证书没问题依旧报错,检查HTTPS证书,ssl证书,使用浏览器测试访问证书是正常的,不是证书问题,请

🏆 前端领域优质创作者 1万+

查看虚函数表

上网搜了半天,没找到好的,自己看了一下,在linux的gdb环境下有比较简单的方法可以看 在blog里记录一下,免得自己忘了 1. 查看函数地址     看函数在代码的哪一行,使用info line就可以看到类似下面这中输出 点击(此处)折叠或打开 (gdb) info line a.cpp:10 Line 10 of "a.cpp" starts

愿世界和平的IT劝退师 2013

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

模块二:C++核心能力进阶(5篇)第四篇《C++对象模型:虚函数表与继承体系内存布局》

《C++对象模型深度解析与GDB调试实战》摘要 本文通过GDB调试技术深入剖析C++对象模型的核心机制,包含三大核心内容:1)虚函数表构建规则与动态绑定流程,详解单/多/虚拟继承的内存布局差异;2)GDB高级调试技法,包括虚表解析脚本、构造过程追踪和内存泄漏定位;3)实战优化方案,涉及虚函数性能测量、内存布局优化及跨平台调试策略。通过30+案例和编译器源码分析,读者将掌握对象生命周期管理、this指针调整等底层原理,以及C++11/14新特性对对象模型的影响。文章还对比了GCC/MSVC实现差异,并提供了标

asuf1364的博客 993

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

C++多态核心原理深度解析:从虚函数表到设计模式实战

面向对象编程(OOP)是软件设计的核心范式,其核心思想在于通过封装、继承和多态来构建灵活、可复用的代码结构。多态作为OOP的关键特性,其原理在于允许程序在运行时根据对象的实际类型来调用相应的方法,这主要通过虚函数和动态绑定机制实现。这项技术的核心价值在于极大地提升了代码的扩展性和可维护性,使得程序能够在不修改现有代码的基础上,通过增加新的派生类来引入新的行为。在工程实践中,多态是构建插件系统、框架以及实现多种设计模式(如工厂模式、策略模式)的基石。理解其底层机制,特别是虚函数表(vtable)的工作原理,对

weixin_33863087的博客 319

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

gdb查看虚函数表、函数地址

1. 查看函数地址 看函数在代码的哪一行,使用info line就可以看到类似下面这中输出 点击(此处)折叠或打开 (gdb) info line a.cpp:10 Line 10 of "a.cpp" starts at address 0x80487d4 <_ZN1B5test2Ev> and ends at 0x80487d7 <_ZN1B5...

weixin_30627341的博客 1917

手写C++17无锁发布-订阅框架:环形缓冲区与内存序实战

发布-订阅模式是现代分布式系统与实时嵌入式通信的核心范式,其本质是解耦数据生产者与消费者的消息传递机制。实现可靠Pub/Sub需深入理解内存模型、原子操作语义及无锁数据结构原理,尤其在资源受限或低延迟场景下,标准队列无法满足确定性调度与零动态分配要求。环形缓冲区凭借缓存友好性、编译期容量约束和免锁读写能力,成为高性能IPC的首选底层结构;而正确使用memory_order_acquire/release与atomic_thread_fence,则直接决定消息可见性与一致性。本文聚焦C++17原生实现,覆盖消

weixin_33739523的博客 379

Whisper.cpp深度解析:C/C++离线语音识别引擎原理与工程实践

语音识别作为人机交互核心能力,其边缘部署长期受限于Python生态的启动开销、内存不可控和依赖复杂等问题。Whisper.cpp通过纯C/C++重实现推理流水线,结合ggml张量库与混合量化技术,实现了低延迟、确定性内存占用和跨平台离线运行。它不依赖Python或GPU,支持ARM/RISC-V等嵌入式架构,适用于智能硬件、车载语音、会议记录等对实时性与可靠性要求严苛的场景。本文围绕C/C++实现、离线运行、嵌入式友好三大关键词,系统剖析其设计哲学、编译调优、流式处理及量产级稳定性保障机制。

weixin_33871366的博客 339

[C++]面向对象编程在C++语言中的实现与应用研究

本文系统分析了 C++ 中面向对象机制的底层实现原理,并探讨其在工业级应用中的实践价值。C++ 在继承 C 语言高效性的同时,引入了类(Class)、对象(Object)、虚函数(Virtual Function)、模板(Template)等机制,成为系统级与大规模应用开发的主要工具。类(Class) 是 C++ 的核心抽象单元,提供数据(成员变量)与行为(成员函数)的封装。- Actor 组件化:通过类继承构建 `Actor`、`Character`、`Weapon` 等对象层次,实现模块化场景开发。

VWRAbkOk的博客 315
上一篇: C++基础#12:多态性与虚函数,重载函数,纯虚函数
下一篇: C++基础#13:模板在C++中的使用,Template
liranke
博客等级 码龄20年 4939粉丝 594原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liranke

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值