C++的多态是如何体现的?一篇文章搞懂C++虚函数机制与常见问题

C++的多态是如何体现的?
一篇尽量清晰、结构化的文章,帮你搞懂虚函数机制、vtable、虚表指针,以及最容易出错的那些点。

1. 多态在C++里到底是什么?

C++支持三种多态:

  • 编译时多态(静态多态):函数重载、运算符重载、模板(泛型)、CRTP
  • 运行时多态(动态多态):通过虚函数 + 指针/引用实现
  • 强制多态(类型转换):static_cast、dynamic_cast 等(较少讨论)

绝大多数人问“C++的多态”时,指的其实就是运行时多态,也就是通过虚函数实现的动态绑定

一句话总结核心:

同一个接口,不同的对象表现出不同的行为,且绑定发生在运行时。

2. 虚函数机制的核心——虚表(vtable)与虚表指针(vptr)

C++的运行时多态实现依赖于以下几个关键概念:

概念英文存放在哪里内容是什么谁拥有它
虚函数表virtual table (vtable)静态存储区(每个类一份)该类的所有虚函数的地址(函数指针数组)类(类型)
虚表指针virtual pointer (vptr)对象内存布局最开头(通常)指向本对象对应类的vtable的指针每个对象
虚函数调用dynamic dispatch通过vptr找到vtable,再通过槽位找到函数地址运行时

最重要的一句话:

只要一个类有虚函数(或继承自有虚函数的类),编译器就会为这个类生成一张虚表,并在类的对象中偷偷插入一个虚表指针 vptr。

3. 虚函数调用流程(最关键的图解过程)

假设有下面这段经典代码:

classAnimal{public:virtualvoidspeak(){ std::cout <<"Animal speaks\n";}virtual~Animal()=default;};classDog:publicAnimal{public:voidspeak()override{ std::cout <<"Woof!\n";}};classCat:publicAnimal{public:voidspeak()override{ std::cout <<"Meow~\n";}};intmain(){ Animal* p =newDog(); p->speak();// 输出 Woof!delete p;}

运行时发生了什么?

  1. 创建 Dog 对象时,编译器在对象内存最开头放了一个 vptr它指向 Dog类的虚表
  2. Dog 类的虚表里,speak() 这一槽位存的是 Dog::speak 的地址。
  3. 调用 p->speak() 时:
    • 取 p 指向对象的 vptr
    • 通过 vptr 找到 虚表
    • 根据 speak() 在虚表中的偏移(槽位索引),取出函数地址
    • 调用该地址 → 执行 Dog::speak()

这就是动态绑定的完整过程。

4. 常见问题与陷阱(面试+实际开发高频)

4.1 构造函数里调用虚函数会怎样?
classBase{public:Base(){whoami();}virtualvoidwhoami(){ std::cout <<"Base\n";}};classDerived:publicBase{public:voidwhoami()override{ std::cout <<"Derived\n";}};intmain(){ Derived d;// 输出 Base}

结论:在构造函数中,vptr 还没有指向派生类的虚表,此时调用虚函数走的是当前正在构造的类的版本。

4.2 析构函数必须是虚函数吗?

必须(只要这个类可能会被指针/引用多态删除)。

原因:如果基类析构不是虚函数,delete base_ptr; 时只调用基类析构,派生类部分不会被析构 → 资源泄漏。

4.3 override 和 final 关键字(C++11+)
virtualvoidf()override;// 明确告诉编译器:我在重写,必须匹配基类签名virtualvoidg()final;// 告诉编译器:这个虚函数到此为止,不允许再被重写

强烈建议在重写时都写 override,能尽早发现签名不匹配的错误。

4.4 纯虚函数 & 抽象类
virtualvoidspeak()=0;// 纯虚函数 → 该类成为抽象类,不能实例化
4.5 虚函数表是每个类一份,还是每个对象一份?

每个有虚函数的类一份(静态的),对象只持有一个指向它的指针。

4.6 多继承下的虚表(最复杂的情况)

多继承时,一个对象可能有多个 vptr(每个继承链一条),虚表也更复杂,还涉及虚基类表(vbptr / vbase)

classA{virtualvoidf();};classB{virtualvoidg();};classC:publicA,publicB{...};

C 的对象内存布局里通常会有 两个 vptr

这是多继承最容易出问题的地方(菱形继承 + 虚继承才能解决二义性)。

4.7 虚函数开销有多大?
  • 空间:每个对象多一个指针(通常 8 字节,64位系统)
  • 时间:一次间接寻址(vptr → vtable → 函数地址),现代 CPU 分支预测 + 内联缓存后开销很小

绝大多数业务场景下,虚函数的性能开销是可以接受的

5. 总结:一句话记住虚函数机制

C++运行时多态 = 虚函数 + 指针/引用 + vtable + vptr + 动态分派

最简记忆口诀

“对象藏 vptr → vptr 指 vtable → vtable 存函数地址 → 运行时查表调用”

希望这篇文章让你对 C++ 虚函数从“会用”变成“知道为什么这样实现”。

如果你还有具体想深入的点(比如:多继承虚表布局、虚函数与模板的冲突、CRTP 静态多态对比、vtable 如何调试查看等),可以直接告诉我,我继续展开。

Read more

Diffusers AI绘画入门:3分钟从零到创作的艺术之旅

Diffusers AI绘画入门:3分钟从零到创作的艺术之旅 【免费下载链接】diffusersDiffusers:在PyTorch中用于图像和音频生成的最先进扩散模型。 项目地址: https://gitcode.com/GitHub_Trending/di/diffusers 在AI绘画的世界里,你是否曾经羡慕那些能够用几行代码就创造出惊艳图像的技术大神?现在,让我带你走进Diffusers的神奇世界,用最简单的方式开启你的AI艺术创作之旅! 为什么选择Diffusers? Diffusers是当前最受欢迎的AI绘画库之一,它让复杂的扩散模型变得触手可及。无论你是编程新手还是艺术爱好者,都能在这里找到创作的乐趣。想象一下,用简单的文字描述就能生成你脑海中的画面,这就是Diffusers带给我们的魔法。 Diffusers生成的多风格图像对比,展示了AI绘画的多样性和创造力 快速配置:零基础也能轻松上手 环境准备(3步搞定) 1. 创建专属环境 python -m venv ai_painting source ai_painting/bin/activate

By Ne0inhk

llama.cpp加载多模态gguf模型

llama.cpp预编译包还不支持cuda12.6 llama.cpp的编译,也有各种坑 llama.cpp.python的也需要编译 llama.cpp命令行加载多模态模型 llama-mtmd-cli -m Qwen2.5-VL-3B-Instruct-q8_0.gguf --mmproj Qwen2.5-VL-3B-Instruct-mmproj-f16.gguf -p "Describe this image." --image ./car-1.jpg **模型主gguf文件要和mmporj文件从一个库里下载,否则会有兼容问题,建议从ggml的官方库里下载 Multimodal GGUFs官方库 llama.cpp.python加载多模态模型 看官方文档 要使用LlamaChatHandler类,官方已经写好了不少多模态模型的加载类,比如qwen2.5vl的写法: from llama_cpp import Llama

By Ne0inhk
2026年Midjourney AI 图像生成器使用教程详解

2026年Midjourney AI 图像生成器使用教程详解

Midjourney 是一款领先的 AI 图像生成工具,用户只需输入简单的文本描述(提示词),即可快速生成高质量、富有艺术感的图像。它主要通过 Discord 平台操作,无需本地安装,但需要订阅付费计划。本文将系统介绍 Midjourney 的核心功能、详细使用教程、价格方案以及提升出图效果的实用技巧,适合设计师、内容创作者和 AI 绘画新手阅读。 一、什么是 Midjourney? Midjourney 是一个由独立研究实验室开发的人工智能图像生成程序,能够根据用户输入的文字描述生成数字图像。它通过深度学习模型理解自然语言,并将其转化为细节丰富、风格多样的视觉作品。 由于其出色的艺术表现力和视觉冲击力,Midjourney 已成为设计师、插画师、品牌创意人员以及 AI 爱好者广泛使用的工具之一。 Midjourney 核心特点 * 文本生成图像:将抽象想法直接转化为可视画面 * 高艺术质量:在光影、构图、风格化方面尤为出色 * 云端运行:通过 Discord 操作,

By Ne0inhk
llama.cpp重大更新:自带Web UI,性能超越Ollama,本地大模型部署新选择!

llama.cpp重大更新:自带Web UI,性能超越Ollama,本地大模型部署新选择!

Ollama 背后执行推理的核心技术其实是由 llama.cpp 承担的,GGUF 模型格式也是由 llama.cpp 的作者所开发。 现在 llama.cpp 迎来重大更新,它也有了自己的 Web UI,我测试了安装部署和自行打包,很多地方确实比 Ollama 还有方便好用。 官方介绍,优势如下: * 完全免费、开源且由社区驱动 * 在所有硬件上表现出色 * 高级上下文和前缀缓存 * 并行和远程用户支持 * 极其轻量级且内存高效 * 充满活力且富有创造力的社区 * 100% 隐私 使用之前需要先安装 llama.cpp server 我还是喜欢命令行直接安装 ## Winget (Windows)winget install llama.cpp## Homebrew (Mac and Linux)brew install llama.

By Ne0inhk