news 2026/3/12 20:28:30

C++拓展:虚函数表的深入探索

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++拓展:虚函数表的深入探索
1.1 单继承下的虚函数表结构

单继承是最基础的继承形式,其虚函数表结构相对简单。我们通过以下示例分析:

代码语言:javascript

AI代码解释

#include <iostream> using namespace std; // 基类 class Base { public: virtual void func1() { cout << "Base::func1()" << endl; } virtual void func2() { cout << "Base::func2()" << endl; } private: int _b; }; // 派生类(单继承Base) class Derive : public Base { public: // 重写Base的func1 virtual void func1() { cout << "Derive::func1()" << endl; } // 新增虚函数 virtual void func3() { cout << "Derive::func3()" << endl; } private: int _d; }; int main() { Base b; Derive d; return 0; }
1.1.1 基类(Base)的虚函数表

Base类包含两个虚函数func1func2,其虚函数表结构如下:

  • 表中依次存储func1func2的函数指针
  • 虚函数表位于代码段(常量区),与对象实例的内存空间分离
  • Base 类的对象b包含一个 vptr(4 字节 / 8 字节,取决于 32/64 位程序)和成员变量_b

通过 VS 的内存窗口观察Base对象的vptr指向的地址(虚函数表起始地址),可看到表中存储的两个函数指针,分别对应Base::func1Base::func2

1.1.2 派生类(Derive)的虚函数表

Derive 类继承自 Base 并做了两件事:重写func1、新增func3。其虚函数表有如下特点:

  1. 继承基类的虚函数表结构,重写的func1替换表中对应位置的函数指针(现在指向Derive::func1);
  2. 未重写的func2仍然指向Base::func2
  3. 新增的虚函数func3被追加到虚函数表的末尾;
  4. Derive 对象d的内存布局为:vptr → 基类成员_b→ 派生类成员_d。

我们通过调试工具查看 Derive 对象的 vptr 指向的虚函数表,会发现前两个条目分别为Derive::func1Base::func2,第三个条目为Derive::func3,完全符合上述结构。

1.2 单继承中虚函数表的访问机制

当使用基类指针指向派生类对象时,通过指针调用虚函数会触发动态绑定,其过程依赖虚函数表:

代码语言:javascript

AI代码解释

int main() { Base* ptr = new Derive(); ptr->func1(); // 调用Derive::func1() ptr->func2(); // 调用Base::func2() // ptr->func3(); // 编译错误:Base类无func3声明 delete ptr; return 0; }

动态绑定的执行步骤:

  1. ptr指向的对象中取出vptr(此时指向 Derive 的虚函数表);
  2. 根据虚函数在表中的偏移量找到对应的函数指针(func1在表中索引为 0,func2索引为 1);
  3. 调用函数指针指向的实际函数。

注意:基类指针是无法直接调用派生类新增的虚函数的(如func3),因为基类中没有该函数的声明,编译器无法确定其在虚函数表中的偏移量。

1.3 单继承下的虚析构函数与虚函数表

析构函数是否为虚函数直接影响对象销毁时的行为。当基类析构函数为虚函数时,其派生类析构函数会自动成为虚函数,并被加入虚函数表:

代码语言:javascript

AI代码解释

class Base { public: virtual ~Base() { cout << "Base::~Base()" << endl; } // 虚析构 virtual void func() { cout << "Base::func()" << endl; } }; class Derive : public Base { public: ~Derive() { cout << "Derive::~Derive()" << endl; } // 自动为虚函数 }; int main() { Base* ptr = new Derive(); delete ptr; // 正确调用Derive::~Derive()和Base::~Base() return 0; }

此时 Derive 的虚函数表中,析构函数的位置会替换基类析构函数的位置,确保delete基类指针时能调用派生类的析构函数,避免内存泄漏。

二、多继承下的虚函数表:结构与访问规则

多继承允许一个类同时继承多个基类,这会导致虚函数表结构变得复杂。根据基类是否包含虚函数,多继承的虚函数表可分为多种情况。

2.1 多继承(无虚函数覆盖)的虚函数表

当派生类继承多个基类且不重写任何虚函数时,每个基类的虚函数表会被独立保留,派生类新增的虚函数通常追加到第一个基类的虚函数表中。

代码语言:javascript

AI代码解释

class Base1 { public: virtual void func1() { cout << "Base1::func1()" << endl; } virtual void func2() { cout << "Base1::func2()" << endl; } int _b1; }; class Base2 { public: virtual void func3() { cout << "Base2::func3()" << endl; } virtual void func4() { cout << "Base2::func4()" << endl; } int _b2; }; // 多继承Base1和Base2 class Derive : public Base1, public Base2 { public: virtual void func5() { cout << "Derive::func5()" << endl; } // 新增虚函数 int _d; };
2.1.1 内存布局分析

Derive 对象的内存结构包含:

  1. 第一个基类 Base1 的部分:vptr1(指向 Base1 的虚函数表)→_b1
  2. 第二个基类 Base2 的部分:vptr2(指向 Base2 的虚函数表)→_b2
  3. 派生类自身部分:_d

对应的虚函数表结构:

  • vptr1 指向的表:Base1::func1Base1::func2Derive::func5(新增函数追加到第一个表)
  • vptr2 指向的表:Base2::func3Base2::func4

验证代码:通过打印虚函数表内容可直观看到这一结构:

代码语言:javascript

AI代码解释

// 打印虚函数表(简化实现,仅用于演示) typedef void(*VFPTR)(); // 定义虚函数指针类型 void PrintVTable(VFPTR* vtable) { cout << "虚函数表地址:" << vtable << endl; for (int i = 0; vtable[i] != nullptr; ++i) { cout << "第" << i << "个虚函数地址:" << vtable[i]; VFPTR f = vtable[i]; f(); // 调用虚函数 } cout << endl; } int main() { Derive d; // 取出第一个虚函数表(Base1的表) VFPTR* vtable1 = (VFPTR*)(*(int*)&d); PrintVTable(vtable1); // 取出第二个虚函数表(Base2的表):Base1部分的大小为vptr(4字节) + _b1(4字节) = 8字节 VFPTR* vtable2 = (VFPTR*)(*(int*)((char*)&d + sizeof(Base1))); PrintVTable(vtable2); return 0; }

输出结果为:

2.2 多继承(有虚函数覆盖)的虚函数表

当派生类重写多个基类中的虚函数时,每个基类的虚函数表中对应的函数指针都会被替换。

代码语言:javascript

AI代码解释

class Base1 { public: virtual void func1() { cout << "Base1::func1()" << endl; } virtual void func2() { cout << "Base1::func2()" << endl; } }; class Base2 { public: virtual void func1() { cout << "Base2::func1()" << endl; } // 与Base1的func1同名 virtual void func3() { cout << "Base2::func3()" << endl; } }; class Derive : public Base1, public Base2 { public: // 同时覆盖Base1和Base2的func1 virtual void func1() { cout << "Derive::func1()" << endl; } };
2.2.1 虚函数表的覆盖规则

Derive 的虚函数表结构如下:

  • Base1 的虚函数表:Derive::func1(覆盖)→Base1::func2
  • Base2 的虚函数表:Derive::func1(覆盖)→Base2::func3

这意味着,无论通过 Base1 指针还是 Base2 指针调用func1,最终都会执行Derive::func1

www.dongchedi.com/article/7595302803858293310
www.dongchedi.com/article/7595302533728551486
www.dongchedi.com/article/7595303526705152574
www.dongchedi.com/article/7595302533728911934
www.dongchedi.com/article/7595302732916277822
www.dongchedi.com/article/7595300345145164313
www.dongchedi.com/article/7595287730565710361
www.dongchedi.com/article/7595287469617529368
www.dongchedi.com/article/7595289256520663576
www.dongchedi.com/article/7595287092394000920
www.dongchedi.com/article/7595286612611957273
www.dongchedi.com/article/7595285133738410521
www.dongchedi.com/article/7595285905729487384
www.dongchedi.com/article/7595287514580435481
www.dongchedi.com/article/7595285072006382105
www.dongchedi.com/article/7595285719334502936
www.dongchedi.com/article/7595285631619007000
www.dongchedi.com/article/7595277509785453081
www.dongchedi.com/article/7595276630432760345
www.dongchedi.com/article/7595275735409967640
www.dongchedi.com/article/7595277089067549246
www.dongchedi.com/article/7595276413155295769
www.dongchedi.com/article/7595276373905195544
www.dongchedi.com/article/7595274144955499033
www.dongchedi.com/article/7595274423667048984
www.dongchedi.com/article/7595275907217195545
www.dongchedi.com/article/7595274913787953689
www.dongchedi.com/article/7595274806057337368
www.dongchedi.com/article/7595274833727406617
www.dongchedi.com/article/7595255011878208062
www.dongchedi.com/article/7595255232834159166
www.dongchedi.com/article/7595244636982379033
www.dongchedi.com/article/7595246619336000062
www.dongchedi.com/article/7595245102663352894
www.dongchedi.com/article/7595246113737982526
www.dongchedi.com/article/7595238963515146814
www.dongchedi.com/article/7595238605032292888
www.dongchedi.com/article/7595237840809198105
www.dongchedi.com/article/7595237829975212569
www.dongchedi.com/article/7595237024668877336
www.dongchedi.com/article/7594914712018600510
www.dongchedi.com/article/7594913283375907352
www.dongchedi.com/article/7594914016129106456
www.dongchedi.com/article/7594914424213766718
www.dongchedi.com/article/7594913083894891033
www.dongchedi.com/article/7594913119710069310
www.dongchedi.com/article/7594912459706696254
www.dongchedi.com/article/7594911633613390360
www.dongchedi.com/article/7594909036307595800
www.dongchedi.com/article/7594910057444786750
www.dongchedi.com/article/7594909893274927641
www.dongchedi.com/article/7594909974816588350
www.dongchedi.com/article/7594909035217404441
www.dongchedi.com/article/7594908551181615678
www.dongchedi.com/article/7594906883010855486
www.dongchedi.com/article/7594907513641058878
www.dongchedi.com/article/7594905549272285720
www.dongchedi.com/article/7594906861996884505
www.dongchedi.com/article/7594906134906421785
www.dongchedi.com/article/7594905869373096472
www.dongchedi.com/article/7594904114086560281
www.dongchedi.com/article/7594903301414650392
www.dongchedi.com/article/7594901235942228542
www.dongchedi.com/article/7594901805579452953
www.dongchedi.com/article/7594900315275657752
www.dongchedi.com/article/7594899458794799641
www.dongchedi.com/article/7594900266315645465
www.dongchedi.com/article/7594900151853236798
www.dongchedi.com/article/7594898846111580697
www.dongchedi.com/article/7594899021756776984


www.dongchedi.com/article/7594897166766965272
www.dongchedi.com/article/7594897310665245246
www.dongchedi.com/article/7594897192310407705
www.dongchedi.com/article/7594897631617794585
www.dongchedi.com/article/7594896580080435737
www.dongchedi.com/article/7594895704896684568
www.dongchedi.com/article/7594897374330503705
www.dongchedi.com/article/7594895618720449048
www.dongchedi.com/article/7594896034183397912
www.dongchedi.com/article/7594896087656694334

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/9 15:59:36

bert-base-chinese教程:中文文本情绪分析应用

bert-base-chinese教程&#xff1a;中文文本情绪分析应用 1. 引言 随着自然语言处理技术的快速发展&#xff0c;预训练语言模型已成为中文文本理解任务的核心工具。在众多模型中&#xff0c;bert-base-chinese 作为 Google 发布的经典中文 BERT 模型&#xff0c;凭借其强大的…

作者头像 李华
网站建设 2026/3/9 15:49:23

IQuest-Coder-V1在DevOps中的应用:基础设施即代码生成

IQuest-Coder-V1在DevOps中的应用&#xff1a;基础设施即代码生成 1. 引言 1.1 DevOps与自动化演进的挑战 在现代软件交付体系中&#xff0c;DevOps 已成为提升研发效率、保障系统稳定性的核心实践。其关键支柱之一是“基础设施即代码”&#xff08;Infrastructure as Code,…

作者头像 李华
网站建设 2026/3/11 17:10:01

AI手势识别与追踪实时性保障:帧率优化实战方案

AI手势识别与追踪实时性保障&#xff1a;帧率优化实战方案 1. 引言 1.1 业务场景描述 在人机交互、虚拟现实、智能监控和远程教育等应用场景中&#xff0c;AI手势识别与追踪技术正逐步成为核心感知能力之一。用户通过自然的手势即可完成指令输入&#xff0c;极大提升了操作的…

作者头像 李华
网站建设 2026/3/11 6:59:50

5分钟部署Whisper语音识别:多语言转文字一键搞定

5分钟部署Whisper语音识别&#xff1a;多语言转文字一键搞定 1. 引言&#xff1a;为什么需要快速部署的语音识别服务&#xff1f; 在内容创作、会议记录、教育转录和客户服务等场景中&#xff0c;高效准确的语音识别能力正成为关键基础设施。OpenAI推出的Whisper系列模型&…

作者头像 李华
网站建设 2026/3/12 10:27:17

容器化微信新体验:Docker部署让跨平台使用更简单

容器化微信新体验&#xff1a;Docker部署让跨平台使用更简单 【免费下载链接】docker-wechat 在docker里运行wechat&#xff0c;可以通过web或者VNC访问wechat 项目地址: https://gitcode.com/gh_mirrors/docke/docker-wechat 还在为不同设备间的微信同步而烦恼吗&#…

作者头像 李华
网站建设 2026/3/10 13:45:08

STM32 CANFD时间戳功能应用:高精度同步通信实例

STM32 CANFD时间戳实战&#xff1a;如何让多节点系统“秒级同步”变成微秒级对齐&#xff1f;你有没有遇到过这样的场景&#xff1f;在调试一个四轴伺服控制系统时&#xff0c;主控明明下发了同一时刻的位置指令&#xff0c;但四个电机的响应却总是有微妙的错位——有的快几毫秒…

作者头像 李华