跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ 多态底层实现原理详解

C++ 多态依赖虚函数表指针与虚函数表实现运行时绑定。含虚函数的类对象增加虚表指针,导致内存对齐后大小变化。基类指针调用虚函数时,通过对象内的虚表指针找到对应虚函数地址执行,而非编译期静态绑定。虚表通常存储在代码段常量区,不同派生类拥有独立虚表,重写函数会覆盖基类虚表项。

CloudNative发布于 2026/3/28更新于 2026/6/113 浏览
C++ 多态底层实现原理详解

C++ 多态底层实现原理详解

在讨论多态的语法层面(如虚函数、override、final)之后,很多开发者对底层的运行机制仍有疑问:为什么带虚函数的类 sizeof 会变大?基类指针如何找到派生类的函数?虚表存在哪里?本文将从内存布局、对象模型及汇编视角,彻底剖析 C++ 多态的实现机制。

一、虚函数与普通函数的区别

我们可以通过一个简单的内存大小测试来切入。考虑以下代码:

class Base {
public:
    virtual void Func1() {
        cout << "Func1()" << endl;
    }
protected:
    int _b = 1;
    char _ch = 'x';
};

int main() {
    Base b;
    cout << sizeof(b) << endl;
    return 0;
}

对于普通类,成员函数不占用对象内存空间,仅数据成员计入大小。上述类中 _b 占 4 字节,_ch 占 1 字节,按内存对齐后通常为 8 字节。但实际运行结果为 12 字节。

这是因为编译器在含有虚函数的类对象中插入了一个隐藏的指针,称为虚函数表指针(vptr)。每个含虚函数的类对象至少包含一个 vptr,用于指向该类的虚函数表(vtable)。这个指针的大小取决于系统架构(32 位为 4 字节,64 位为 8 字节),正是它导致了对象大小的增加。

二、多态的实现原理

1. 动态绑定机制

多态的核心在于运行时决定调用哪个函数。当通过基类指针或引用调用虚函数时,编译器不会直接生成函数地址,而是生成一段查找逻辑:

  1. 通过对象中的 vptr 找到虚函数表。
  2. 根据虚函数在表中的偏移量获取函数地址。
  3. 跳转到该地址执行。

这意味着,虽然指针类型是基类,但实际调用的函数取决于指针当前指向的对象类型。

class Person {
public:
    virtual void BuyTicket() {
        cout << "买票 - 全价" << endl;
    }
private:
    string _name;
};

class  :  Person {
:
    {
        cout <<  << endl;
    }
:
    string _id;
};

  :  Person {
:
    {
        cout <<  << endl;
    }
:
    string _codename;
};

{
    
    
    ptr->();
}

{
    Person ps;
    Student st;
    Soldier sr;
    (&ps); 
    (&st); 
    (&sr); 
     ;
}
Student
public
public
virtual void BuyTicket()
"买票 - 打折"
private
class
Soldier
public
public
virtual void BuyTicket()
"买票 - 优先"
private
void Func(Person* ptr)
// 这里可以看到虽然都是 Person 指针,
// 但是跟 ptr 没关系,而由 ptr 指向的对象决定的。
BuyTicket
int main()
Func
// 输出:买票 - 全价
Func
// 输出:买票 - 打折
Func
// 输出:买票 - 优先
return
0

2. 静态绑定与动态绑定

  • 静态绑定:不满足多态条件(如非虚函数、通过对象名调用)时,编译器在编译期确定函数地址,效率较高。
  • 动态绑定:满足多态条件(指针/引用 + 虚函数)时,在运行期通过虚表查找地址。

从汇编层面看,动态绑定涉及间接寻址(mov eax, dword ptr [edx] 然后 call eax),而静态绑定则是直接跳转(call func_address)。

3. 虚函数表结构

  • 存储位置:虚函数表本身通常存储在代码段(常量区),而非堆或栈。不同编译器实现可能略有差异,VS 和 GCC 均倾向于将其放在只读区域。
  • 独立性:同类型的对象共享同一张虚表,但基类和派生类拥有各自独立的虚表。
  • 覆盖机制:派生类重写基类虚函数时,派生类虚表中对应位置的地址会被更新为派生类函数的地址。
  • 内容构成:派生类虚表包含继承下来的虚函数地址(可能被覆盖)、新增加的虚函数地址。部分编译器会在表尾添加 0x00000000 作为结束标记,但这并非标准规定。
class Base {
public:
    virtual void func1() { cout << "Base::func1" << endl; }
    virtual void func2() { cout << "Base::func2" << endl; }
    void func5() { cout << "Base::func5" << endl; }
protected:
    int a = 1;
};

class Derive : public Base {
public:
    virtual void func1() { cout << "Derive::func1" << endl; }
    virtual void func3() { cout << "Derive::func3" << endl; }
    void func4() { cout << "Derive::func4" << endl; }
protected:
    int b = 2;
};

int main() {
    Base b;
    Derive d;
    Base* p3 = &b;
    Derive* p4 = &d;
    
    // 打印虚表地址对比
    printf("Person 虚表地址:%p\n", *(int*)p3);
    printf("Student 虚表地址:%p\n", *(int*)p4);
    printf("虚函数地址:%p\n", &Base::func1);
    printf("普通函数地址:%p\n", &Base::func5);
    return 0;
}

运行结果通常显示虚表地址位于常量区,与普通函数地址相近,而与栈、堆地址有明显区分。这证实了虚表属于全局只读数据的一部分。

理解这些底层细节,有助于我们在设计接口时更好地权衡性能与灵活性,避免不必要的虚函数开销。

目录

  1. C++ 多态底层实现原理详解
  2. 一、虚函数与普通函数的区别
  3. 二、多态的实现原理
  4. 1. 动态绑定机制
  5. 2. 静态绑定与动态绑定
  6. 3. 虚函数表结构
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • uv 虚拟环境实战:创建、激活与版本控制
  • 鸿蒙金融理财全栈项目:基础架构、数据安全与用户体验
  • SpringBoot 集成 Stable-Diffusion-3.5 微服务实践
  • OpenClaw 配置飞书机器人与 Kimi 2.5 接入指南
  • Redis Zset 底层实现:跳跃表与字典
  • Windows 下安装 OpenClaw 并接入飞书机器人实战指南
  • Java外部内存API详解:核心概念、五大使用场景与最佳实践
  • CUDA 12.4 入门:GPU 优势与可扩展编程模型
  • 基于 Nexent 知识库与 MCP 生态打造智能烹饪顾问实战
  • MonkeyCode 全流程 AI 编程协作工具技术解析
  • C语言在无人机传感器处理中的核心技术与优化实践
  • Python 网络流量分析与入侵检测系统
  • Eino ADK 核心解析:为什么 Agent 必须是一层独立抽象
  • C++ string::find 方法详解与使用示例
  • DeepSeek-R1 大模型基于 MS-Swift 框架部署/推理/微调实践
  • 人工智能入门指南:零基础学习与实践
  • JavaScript 空值判断工具函数
  • IDEA 修改 Git 用户配置
  • 黑客入门指南:零基础掌握安全工程师核心能力
  • AI 赋能原则 5:当最聪明的大脑犯低级错误

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online