跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++

C++ 虚函数、多态与绑定机制

C++ 多态通过虚函数实现,核心是绑定机制。对象含虚表指针,类有虚函数表。基类指针调用虚函数时发生动态绑定,由运行时类型决定;非虚函数或按值传递则为静态绑定,编译期确定。构造析构期间虚函数也静态绑定至当前层级。动态绑定需满足虚函数声明、基类指针/引用、完整派生对象三个条件。

山野来信发布于 2026/3/23更新于 2026/5/1219K 浏览
C++ 虚函数、多态与绑定机制

在这里插入图片描述

在这里插入图片描述

在 C++ 中,对象本身只保存数据和一个隐藏的虚表指针(vptr),而所有成员函数的代码都只存在于程序的代码段中。 如果类有虚函数,编译器会为每个类生成一张虚表(vtable),虚表里存放对应虚函数的函数地址。 当创建 Derived 对象时,对象内的 vptr 会指向 Derived::vtable;如果用 Base* 指向这个对象并调用虚函数,程序会在运行时通过 vptr → vtable → 函数地址,最终调用到 Derived::f,这就是动态绑定。 如果是普通对象或按值传递(发生对象切片),就不会经过虚表,而是在编译期直接决定调用 Base::f,这是静态绑定。 构造和析构过程中,vptr 会随着当前构造层级切换,确保虚函数只调用'当前已构造完成'的那一层实现。


引言:为什么需要多态?

设想一个图形绘制系统:

class Shape {
public:
    void draw() { /* 绘制基础形状 */ }
};

class Circle : public Shape {
public:
    void draw() { /* 绘制圆形 */ }
};

class Rectangle : public Shape {
public:
    void draw() { /* 绘制矩形 */ }
};

// 问题来了:如何统一处理?
{
     ( i = ; i < count; i++) {
        shapes[i]->(); 
    }
}
void drawAll(Shape* shapes[], int count)
for
int
0
draw
// 期望:调用实际类型的 draw

核心问题:如何让基类指针调用到正确的派生类函数?

这就引出了多态(Polymorphism)的需求,而实现多态的关键是绑定机制。


一、什么是'绑定(Binding)'

绑定指的是:

在某个时间点,确定'一次函数调用'究竟对应哪一个具体函数实现。

在 C++ 中,绑定主要分为两类:

  • 静态绑定(Static Binding / Early Binding)
  • 动态绑定(Dynamic Binding / Late Binding)

二、静态绑定(Static Binding)

1️⃣ 定义

在编译期就能确定调用目标的绑定方式。

2️⃣ 典型特征
  • 不依赖对象的运行时类型
  • 调用目标在编译期已确定
  • 通常可被内联,性能最好
3️⃣ 发生静态绑定的情况
(1)非 virtual 函数
struct Base {
    void f() { std::cout << "Base::f\n"; }
};

struct Derived : Base {
    void f() { std::cout << "Derived::f\n"; }
};

Base* p = new Derived;
p->f(); // 静态绑定,调用 Base::f,输出 "Base::f"

解析:

  • 编译器看到 p 类型是 Base*
  • f() 不是虚函数,编译期直接确定调用 Base::f
  • 即使 p 实际指向 Derived 对象,也不会调用 Derived::f
(2)按值调用(对象切片)
void process(Base b) { // 按值传递
    b.f(); // 始终调用 Base::f
}

Derived d;
process(d); // 静态绑定,Base::f

切片过程:

  • 传参时构造一个新的 Base 对象
  • 只拷贝 Derived 中的 Base 部分
  • Derived 的额外数据丢失
  • vptr 被重置为 Base::vtable
(3)构造 / 析构期间的虚函数调用
struct Base {
    Base() { f(); } // 在构造函数中调用
    virtual void f() { std::cout << "Base::f\n"; }
};

struct Derived : Base {
    void f() override { std::cout << "Derived::f\n"; }
};

Derived d; // 输出 "Base::f",不是 "Derived::f"
  • 即使 f 是 virtual
  • 构造期间仍 静态绑定到当前构造层级
4️⃣ 静态绑定的性能优势
// 编译器可能的优化
inline void Base::f() { /* ... */ }
p->f(); // 静态绑定 → 可内联展开 → 无函数调用开销
  • 零运行时开销
  • 可被内联优化
  • 无需查表操作

三、动态绑定(Dynamic Binding)

1️⃣ 定义

在运行时,根据对象的动态类型决定调用哪个函数实现。

2️⃣ 动态绑定的三个必要条件
  1. 函数被声明为 virtual
  2. 通过 基类指针或引用 调用
  3. 指针/引用指向 完整的派生类对象
struct Base {
    virtual void f() { std::cout << "Base::f\n"; }
};

struct Derived : Base {
    void f() override { std::cout << "Derived::f\n"; }
};

Base* p = new Derived;
p->f(); // 动态绑定,输出 "Derived::f"

Base& r = *new Derived;
r.f(); // 动态绑定,输出 "Derived::f"
3️⃣ 完整示例:对比静态与动态绑定
#include <iostream>

struct Base {
    void normalFunc() { std::cout << "Base::normalFunc\n"; }
    virtual void virtualFunc() { std::cout << "Base::virtualFunc\n"; }
};

struct Derived : Base {
    void normalFunc() { std::cout << "Derived::normalFunc\n"; }
    void virtualFunc() override { std::cout << "Derived::virtualFunc\n"; }
};

int main() {
    Derived d;
    return 0;
}

目录

  1. 引言:为什么需要多态?
  2. 一、什么是“绑定(Binding)”
  3. 二、静态绑定(Static Binding)
  4. 1️⃣ 定义
  5. 2️⃣ 典型特征
  6. 3️⃣ 发生静态绑定的情况
  7. (1)非 virtual 函数
  8. (2)按值调用(对象切片)
  9. (3)构造 / 析构期间的虚函数调用
  10. 4️⃣ 静态绑定的性能优势
  11. 三、动态绑定(Dynamic Binding)
  12. 1️⃣ 定义
  13. 2️⃣ 动态绑定的三个必要条件
  14. 3️⃣ 完整示例:对比静态与动态绑定
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • Rust 异步并发安全与内存管理实战指南
  • GitHub 使用指南:环境配置与版本控制流程
  • 高鋒集團黃俊瑯:資本與生態如何賦能傳統企業 Web3 轉型
  • MySQL 事务核心概念与四大特性详解
  • VSCode 中关闭 GitHub Copilot 功能的两种方法
  • Dify 工作流实战:快速搭建 Web 登录界面
  • AI Skills 市场与共享经济架构实战
  • Python 基于 Vue 的黄山旅游网站设计与实现
  • Python 数据分析入门:集中趋势与离散程度实战
  • DeepSeek 辅助降低论文 AIGC 检测率的指令与工具指南
  • 机器学习核心算法实战笔记:从 KNN 到集成学习
  • Rocky Linux 安装教程
  • Docker+Ollama 本地部署 DeepSeek 大模型指南
  • 基于 LangChain+ChatGLM 部署本地私有化知识库
  • Flutter 三方库 ethereum_addresses 的鸿蒙化适配指南
  • TapNow AI 视频平台实测:导演级精准控制与物理一致性解析
  • OpenClaw 基础:Telegram 机器人配置与加入群聊
  • Python 基础语法入门(一)
  • Linux 基础、进阶及常用命令总结
  • C# 开发系列教程

相关免费在线工具

  • 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

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online