【C++ 面试真题】聊聊 C++ 的虚函数和多态
【C 面试真题】聊聊 C 的虚函数和多态虚函数是 C 面试的分水岭——背得出virtual 实现多态只是及格真考你的是虚函数表长什么样、对象内存里存了什么、构造析构里调虚函数会发生什么。一道题能从语法一路问到内存布局。本文把虚函数表、动态多态、纯虚函数串成一条线一次讲透。一、先说结论虚函数 运行期才决定的调用❓ 什么是虚函数它和多态什么关系✅ 一句话虚函数是一种运行期才决定调用哪个版本的成员函数它是 C 实现动态多态的机制。普通成员函数的调用在编译期就定死虚函数的调用要到运行期根据对象实际类型来决定——这就是多态。structAnimal{virtualvoidspeak(){}virtual~Animal()default;};structDog:Animal{voidspeak()override{std::cout汪;}};Animal*anewDog;// 运行期才知道 a 指向 Doga-speak();// 打印汪// 这就是多态a的静态类型是Animal*但实际指向Dog对象。没有 virtuala-speak()会调Animal::speak有了 virtual它会调Dog::speak。这就是动态多态。二、虚函数表多态是怎么实现的❓ 虚函数到底是怎么实现运行期决定调用的✅ 靠虚函数表vtable和虚表指针vptr。这是这题的硬核必须讲清。机制分三层每个有虚函数的类编译器给它生成一张虚函数表——一个存放虚函数地址的数组每个该类的对象内存里多一个虚表指针 vptr指向自己所属类的虚表虚函数调用时通过对象的 vptr 找到虚表再查表调到正确版本。Dog 对象的内存布局 ---------- | vptr ------- Dog 的虚函数表 ---------- ------------ | 成员... | | Dog::speak| ---------- ------------Animal*anewDog;// a-speak() 实际做的事// 1. 通过 a 找到对象里的 vptr// 2. vptr 指向 Dog 的虚表// 3. 查表得到 Dog::speak 的地址// 4. 调用它加分点谁建表、谁设 vptr虚表是编译期就生成好的每个类一张静态数据vptr 是构造函数里设置/更新的——对象构造时vptr 指向自己正在构造的那个类。这就引出后面构造函数里调虚函数的坑。三、静态多态 vs 动态多态❓ 多态只有虚函数这一种吗✅ 不是。C 有两种多态类型时机机制例子静态多态编译期函数重载、模板max(1,2)vsmax(1.0,2.0)动态多态运行期虚函数a-speak()// 静态多态编译期定死templatetypenameTTadd(T a,T b){returnab;}add(1,2);// 调 int 版本add(1.0,2.0);// 调 double 版本// 动态多态运行期才定Animal*anewDog;a-speak();// 运行期查虚表区别静态多态零开销编译期就定没查表但灵活性低动态多态有开销要查虚表、间接调用但能在运行期根据实际类型决定行为。面试常问用模板还是虚函数本质就是这两者的权衡。四、构造/析构里调虚函数经典大坑❓ 在构造或析构函数里调用虚函数会怎样✅不会发生多态——调到的是当前类的版本不是子类的。这是 C 最经典的坑之一。原因对象的 vptr 在构造过程中逐层设置。构造基类时vptr 指向基类进入子类构造后vptr 才更新指向子类。析构则反过来。structBase{Base(){// 此时 vptr 指向 Baseinit();// 调 Base::init// 不是 Der::init}virtualvoidinit(){}virtual~Base()default;};structDer:Base{voidinit()override{}};Der d;// 构造时 Base() 里调的是 Base::init⚠️为什么这么设计构造基类时子类部分还没构造此时调子类的虚函数会用到未初始化的成员——很危险。所以语言规定构造/析构期间的虚函数调用退化为当前类的普通调用。理解了这层保护就不会再踩这个坑。五、纯虚函数与抽象类❓ 什么是纯虚函数抽象类有什么用✅纯虚函数是只有声明、没有定义的虚函数 0。含有纯虚函数的类叫抽象类不能实例化只能作为接口被继承。// 抽象类接口structShape{// 纯虚函数必须由子类实现virtualdoublearea()const0;virtual~Shape()default;};// 子类必须实现 area否则仍是抽象类structCircle:Shape{doubler;doublearea()constoverride{return3.14*r*r;}};// Shape s; // ❌ 抽象类不能实例化Circle c{2.0};Shape*pc;std::coutp-area();// 12.56加分点纯虚函数也可以有定义在类外写Shape::area() {...}子类可显式调用——用于提供默认实现但仍强制子类 override抽象类是 C 实现接口编程的标准手段基类只定契约子类提供实现。六、虚函数的代价❓ 用虚函数有什么开销✅ 三方面代价运行期开销每次虚函数调用要查虚表 间接跳转比普通调用慢且阻碍内联空间开销每个对象多一个vptr通常 8 字节每个类多一张虚表缓存影响间接跳转破坏指令缓存局部性。实践建议虚函数的开销在绝大多数业务代码里可以忽略——一次查表就几纳秒。只有性能敏感的热路径如每帧百万次调用才需要计较那时考虑用模板/CRTP 做静态多态替代。别为了怕慢就不用虚函数那是过早优化。七、核心规则速查表维度规则多态实现虚函数 虚表 vptr虚表生成编译期每个类一张vptr 设置构造函数里逐层更新构造/析构里调虚函数退化为当前类版本不多态纯虚函数 0使类变抽象不可实例化开销查表间接调用每对象多一 vptr八、面试高频追问❓ Q1基类析构函数为什么要是虚函数✅ 当你用基类指针 delete 一个子类对象时若析构不是虚函数只会调基类析构子类析构不执行——子类资源泄漏。这是未定义行为的高发区。所以有虚函数的类析构几乎一定要虚。❓ Q2虚函数能内联吗✅ 语法上能加 inline但通常不会被内联——虚函数要查虚表编译期定不下来。例外编译期能确定实际类型时直接通过对象而非指针/引用调用编译器可能内联掉。❓ Q3虚函数表存在哪✅ 每个类一张是编译期生成的静态只读数据通常在 .rodata 段。所有该类对象共享这一张虚表只是各自的对象里有一个 vptr 指向它。❓ Q4构造函数能是虚函数吗✅不能。虚函数依赖 vptr而 vptr 要在构造函数里设置——构造还没开始vptr 还没就位逻辑上矛盾。所以语言直接禁止虚构造函数。❓ Q5override 和 virtual 写哪个✅ 派生类重写虚函数优先写 override让编译器检查签名。virtual 性质会沿继承链自动传递派生类不写 virtual 也是虚函数但 override 能挡住签名写错导致没重写的 bug见关键字篇 final/override。九、总结速查表概念一句话虚函数运行期决定的成员函数虚表 vtable每类一张存虚函数地址vptr每对象一个指向所属类虚表抽象类含纯虚函数不可实例化多态实现通过 vptr 查 vtable一句话回顾虚函数的本质是用虚表和 vptr 实现运行期决定调用。记住每类一张虚表、每对象一个 vptr、构造析构里调虚函数会退化、基类析构要虚这题就稳了。如果您觉得本篇内容对你有帮助欢迎点赞 、收藏 ⭐、转发 。下期我们聊聊运算符重载敬请关注

相关新闻

Win11Debloat 完整使用指南:免费脚本一键清理 Windows 11 预装软件、广告与遥测

Win11Debloat 完整使用指南:免费脚本一键清理 Windows 11 预装软件、广告与遥测

Win11Debloat 完整使用指南:免费脚本一键清理 Windows 11 预装软件、广告与遥测 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other cha…

2026/10/20 19:05:30 阅读更多 →
OpenReviewer:基于LLM的科学论文审稿意见生成工具部署与应用指南

OpenReviewer:基于LLM的科学论文审稿意见生成工具部署与应用指南

这次我们来看一个专门用于生成科学论文审稿意见的 LLM 项目:OpenReviewer。对于科研人员、期刊编辑和审稿人来说,撰写高质量的同行评议意见是一项耗时且需要深厚专业知识的任务。这个开源项目旨在利用大语言模型(LLM)的能力&#…

2026/10/15 18:31:03 阅读更多 →
ASMR声音设计:从双耳录音到助眠应用的技术解析与实践指南

ASMR声音设计:从双耳录音到助眠应用的技术解析与实践指南

1. 先搞清楚“Gently Drifting ASMR”到底是什么,以及它解决什么问题如果你在找一种能帮你快速放松、专注,甚至辅助睡眠的声音内容,那么“ASMR”这个词你肯定不陌生。而“Gently Drifting ASMR”这个项目,从标题来看,它…

2026/10/20 9:29:54 阅读更多 →

最新新闻

Playwright Fixture机制:模拟数据库与API,根治测试数据污染

Playwright Fixture机制:模拟数据库与API,根治测试数据污染

做Web自动化测试这几年,我在实际项目里总结出三怕:一怕测试环境数据库连不上,二怕第三方接口突然限流,三怕测试数据互相污染。前两个问题会让你辛辛苦苦维护的用例在一夜之间全部标红,第三个问题则更隐蔽——明明昨天还…

2026/10/21 7:59:12 阅读更多 →
Qt 5.15.12 Windows 10下编译32位动态库完整指南

Qt 5.15.12 Windows 10下编译32位动态库完整指南

简介:面向Windows 10 32位应用开发的Qt 5.15.12动态库编译包,基于MSVC2019编译器构建,专为需要维护32位兼容性、或希望避开复杂编译配置的C开发者准备。压缩包内共2000个文件,以Qt头文件(.h)为主&#xff0…

2026/10/21 7:59:12 阅读更多 →
机械臂正运动学入门:从旋转矩阵到DH参数解析

机械臂正运动学入门:从旋转矩阵到DH参数解析

机械臂这个东西,入门时最容易迷惑的不是电机怎么转,而是“我要它去的点”和“它实际到的点”之间到底隔着什么。我刚开始折腾机械臂时,以为把每个舵机角度调到某个值就行,结果想让它末端走一条直线,它硬是在空中画了个…

2026/10/21 7:59:12 阅读更多 →
Java设计模式速通:场景+实战,快速掌握核心模式

Java设计模式速通:场景+实战,快速掌握核心模式

不是每一行代码都值得背下来,但设计模式是少数值得花时间想清楚的东西。尤其是Java生态里,框架源码、中间件、业务系统到处都嵌着这些模式,看不懂它们,读源码就像看天书;看懂了,重构和扩展的底气完全不一样…

2026/10/21 7:59:12 阅读更多 →
zzcms8.3建站系统实战:环境搭建、代码审计与二次开发改造指南

zzcms8.3建站系统实战:环境搭建、代码审计与二次开发改造指南

简介:ZZCMS 8.3 是一套开源内容管理系统源码,面向希望入门代码审计与 PHP 架构的开发者、安全学习者及建站人员。它既可用于搭建动态网站,也是一份可动手剖析的实战样本,帮助读者在真实项目中理解安全编码与设计模式。压缩包为 zi…

2026/10/21 7:59:12 阅读更多 →
EVE新手挖坟逃生指南:反跳、扰频、微曲与泡泡全解析

EVE新手挖坟逃生指南:反跳、扰频、微曲与泡泡全解析

简介:这是一份面向EVE新手玩家的挖坟逃生实操指南,作者结合多年实战经验,系统梳理了遗迹破译与逃生环节最容易翻车的细节。内容从破译箱子时的隐身快捷键设置、环绕距离把握讲起,逐步展开过星门遇泡泡的脱身路线规划、微曲与隐身技…

2026/10/21 7:58:11 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/21 4:27:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →