尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
【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、构造析构里调虚函数会退化、基类析构要虚这题就稳了。如果您觉得本篇内容对你有帮助欢迎点赞 、收藏 ⭐、转发 。下期我们聊聊运算符重载敬请关注
RELATED

相关推荐

从手工流水线到智能驾驶舱:AI Native时代CI/CD的范式演进与实践

从手工流水线到智能驾驶舱:AI Native时代CI/CD的范式演进与实践

1. 从“拧螺丝”到“看仪表盘”:CI/CD的十年之痒如果你在十年前问我什么是CI/CD,我可能会给你画一张图:左边是代码提交,中间是一堆脚本和任务框,右边是部署成功的标志。那时候,我们管这叫“流水线”。但如果…

📅 2026/9/6 0:54:07
RisohEditor(文件资源编译器)

RisohEditor(文件资源编译器)

链接:https://pan.quark.cn/s/b035bd4a7bf4 RisohEditor是一款可以帮助用户编辑资源的应用程序,软件可以显示你打开的资源ID列表,提供多个控件内容,可以添加图标,可以设置资源名字,可以设置资源语言类型&a…

📅 2026/10/6 17:26:42
运维控制台升级:从只读监控到实时诊断的架构设计与安全实践

运维控制台升级:从只读监控到实时诊断的架构设计与安全实践

1. 项目概述:从“看”到“治”的运维体验升级在云原生和微服务架构大行其道的今天,运维控制台(Owner Console)已经成为我们日常工作的核心界面。但不知道你有没有遇到过这样的场景:线上服务出现了一个诡异的偶发性问题…

📅 2026/9/8 16:50:30
MORE NEWS

更多资讯

📰

基于CNN卷积网络的动物疲劳识别毕设实战:从数据构建到模型调参

毕设题目里"基于深度学习python-CNN卷积网络的动物是否疲劳识别"看着挺长,实际拆开就是一件事:用卷积神经网络对动物图像做二分类,判断当前状态是否疲劳。我做完这个方向之后最大的感触是——模型训练反而是整个流程里最简单的一环…

📰

鸿蒙端离线内容净化墙:Flutter插件移植与UGC过滤实践

前阵子我配合某团队在处理一款社区类应用的UGC内容治理,问题很典型:大促之后评论区和私聊里明显多了一批垃圾话、辱骂词和引流话术,服务端策略在跑,但总有一部分内容在接口返回之前已经造成了体验伤害。当时我们内部复盘有一个共识…

📰

SpringBoot篮球场馆预订系统:从数据库建模到并发防超卖实战详解

这段时间帮一位朋友调试一套基于JavaSpringBoot的篮球场馆预订系统,从最初跑通源码再到把调试文档、设计文档(LW)、讲解资料整套整理完,前后花了挺长时间。说实话,这类场地预约平台在课程设计和毕业设计里几乎成了“标…

📰

跨境工业互联网络优化:射频一致性与隧道自愈实战解析

去年我们帮一家制造集团做跨境工业互联的网络优化,产线设备从A园区搬到B园区之后,问题一个接一个:机械臂控制器频繁掉线,AGV小车走着走着就停在原地,跨域数据采集平台能看到设备在线,但下发的控制指令经常石…

📰

从技能盘点到季度复盘:打造可持续增长的个人技能资产

很多人把“skills”理解成简历上那一行行技能清单,比如“熟练使用办公软件”“掌握一门编程语言”。但真正在项目里冲过锋、带过队、独自扛过事的人都会明白:技能不是名词,是动词。它不是你知道什么,而是你能解决什么。这些年我见…

📰

EXBSA提取工具:嵌入式固件中二进制结构体精准解析方案

简介:ExBSA提取工具是一款面向GALGAME爱好者、MOD制作者及逆向分析初学者的开源解包软件,专用于解析BISHOP社视觉小说游戏中的BSA(BISHOP Archive)资源包,解决游戏图像、音频、剧本等素材无法直接访问与再利用的问题。…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬