C++中的虚表和虚表指针的原理和示例

一、基本概念

1. 什么是虚函数(virtual function)?

虚函数是用 virtual 关键字修饰的成员函数,支持运行时多态(dynamic polymorphism)。通过基类指针或引用调用派生类重写的函数。

cpp 复制代码
class Base {
public:
    virtual void speak() { cout << "Base speaking" << endl; }
};

只要类中存在虚函数,编译器就会为该类生成虚表。


2. 什么是虚表(vtable)?

  • vtable 是一个函数指针数组,用于保存该类的所有虚函数的地址。
  • 每个有虚函数的类有一张虚表
  • 如果派生类重写了虚函数,虚表中对应的函数指针将被替换为派生类版本。

3. 什么是虚表指针(vptr)?

  • 每个对象中都有一个隐藏成员变量 vptr(虚表指针),指向该对象所属类的虚表。
  • 对象创建时,构造函数会自动设置 vptr 的值。
  • 调用虚函数时,程序会通过 vptr 找到虚表,再通过表中函数指针找到目标函数,最终调用。

二、图解原理(简化示意)

text 复制代码
对象结构:          虚表结构(函数地址表):

[对象内存]
+---------+        +------------------+
|  vptr   | -----> | &Derived::speak()|
+---------+        +------------------+

三、示例代码与解析

示例:基类与派生类使用虚函数

cpp 复制代码
#include <iostream>
using namespace std;

class Base {
public:
    virtual void speak() {
        cout << "Base::speak()" << endl;
    }
};

class Derived : public Base {
public:
    void speak() override {
        cout << "Derived::speak()" << endl;
    }
};

int main() {
    Base* p = new Derived();  // p 的 vptr 指向 Derived 的虚表
    p->speak();               // 动态绑定,输出 Derived::speak()

    delete p;
    return 0;
}

执行过程(底层原理):

  1. 创建 Derived 对象,构造函数自动设置 vptr,指向 Derived 的虚表;
  2. 虚表中 speak() 的指针是 &Derived::speak()
  3. 调用 p->speak(),程序先通过 vptr 找到虚表,再调用函数指针,最终运行 Derived::speak()

四、进一步理解:虚表模拟(伪代码)

下面是 C++ 编译器幕后自动完成的模拟行为:

cpp 复制代码
class Base {
    void** vptr;  // 隐藏成员:虚表指针
    static void* vtable_Base[] = { &Base::speak };

public:
    virtual void speak();
};

class Derived : public Base {
    static void* vtable_Derived[] = { &Derived::speak };

public:
    void speak() override;
};

你不会在代码中显式看到 vptrvtable,它们是编译器隐藏实现的。


五、相关细节注意

情况 说明
类没有虚函数 不生成 vtable,不支持运行时多态
虚函数未被重写 虚表中仍然是基类函数指针
多重继承 每个父类一套虚表和一个 vptr
析构函数建议设为 virtual 防止只析构父类对象导致内存泄漏
构造函数中调用虚函数 不会发生多态,vptr 还没完全初始化

六、下节预告

1.多重继承下的虚表结构

2.析构函数不设为virtual导致内存泄漏示例

相关推荐
SeaTunnel10 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
碎光拾影10 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
Marst Code11 小时前
(python)2026Plotly 库评估:交互式可视化到底值不值得引入?
开发语言·python
Miao1213111 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
CRMEB系统商城12 小时前
开源自建还是SaaS订阅?算一笔3年经济账
java·大数据·开发语言·开源
王维同学13 小时前
[自学][Windows C++]RunOnceEx 注册表分组键的安全遍历
c++·windows·安全·开源
keyipatience13 小时前
线程栈与TLS和线程互斥
java·linux·服务器·开发语言·ubuntu
我的xiaodoujiao13 小时前
快速学习Python基础知识详细图文教程9--函数进阶
开发语言·python·学习·测试工具
Scott9999HH14 小时前
告别流量波动玄学!从法拉第电磁定律到底层 C/C++ 流量累积算法,深度解密工业级电磁流量计选型与开发
c语言·c++·算法
爱喝水的鱼丶14 小时前
SAP-ABAP:ALV通用封装实践——搭建可复用的ALV开发工具类,减少80%重复代码
开发语言·性能优化·sap·abap·erp·alv