卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
  • 本栏必读

    • 关于本专栏
    • C++学习路线
    • C++面试题系优化
  • 基础与语法

  • 面向对象

    • C++构造函数有几种,分别什么作用?
    • 什么是构造函数和析构函数?构造函数和析构函数可以是虚函数吗?为什么?
    • C++的重载和重写,以及它们的区别和实现方式
    • C++怎么实现多态
      • 简要回答
      • 详细回答
      • 知识拓展
    • C++中的虚函数和纯虚函数有什么区别?
    • 虚函数怎么实现的?
    • 多重继承的优缺点及菱形继承问题
    • 如何禁止一个类被继承
    • 深拷贝和浅拷贝的区别?
    • this指针的原理
    • C++如何实现一个单例模式?
  • STL 与容器

  • 内存管理

  • C++11 与现代 C++

  • 智能指针

  • 并发与 I/O

# C++多态的实现机制

面试官问"C++多态是怎么实现的",很多人只答"虚函数+继承"就停了。但面试官真正想听的是底层怎么走的——vtable 在哪、vptr 什么时候初始化、调用链是怎样的。只说表面概念,面试官一定会追问到你答不上来。

把编译时多态和运行时多态分清楚,再把运行时多态的调用链讲明白,这道题就稳了。

# 简要回答

C++ 多态分两种:编译时多态靠函数重载和模板,编译期就确定调用谁;运行时多态靠 virtual 函数 + 继承 + 基类指针/引用,运行时通过 vptr → vtable → 函数地址 动态绑定到正确的实现。

# 详细回答

维度 编译时多态 运行时多态
实现手段 函数重载、模板 虚函数 + 继承
绑定时机 编译期(静态绑定) 运行期(动态绑定)
关键机制 编译器根据参数类型/模板参数选择 vptr → vtable → 函数地址
触发条件 直接调用即可 必须通过基类指针或引用调用
性能 无额外开销,可内联 多一次间接寻址,无法内联
典型场景 sort 的比较函数、max<T> 基类接口统一调度派生类行为

运行时多态的三个必要条件:基类声明 virtual 函数、派生类重写(override)该函数、通过基类指针或引用调用。三者缺一不可——如果用派生类对象直接调用,编译器会静态绑定,不走 vtable。

虚函数调用的底层流程(以 Animal* p = new Dog(); p->speak(); 为例):

  1. 编译器为每个含虚函数的类生成一张 vtable,表中按声明顺序存放虚函数地址。Dog 的 vtable 中 speak 槽位存的是 Dog::speak 的地址
  2. 每个对象的内存布局最前面藏一个 vptr,构造时指向本类的 vtable
  3. 调用 p->speak() 时:通过 p 找到 Dog 对象 → 取 vptr → 在 vtable 中查 speak 的偏移 → 跳转执行 Dog::speak()

这就是为什么基类析构函数必须声明为 virtual——否则 delete p 时只调基类析构,派生类资源泄漏。

C++多态虚函数调用流程

# 知识拓展

Q:抽象类和纯虚函数是什么关系?

含有纯虚函数(virtual void run() = 0;)的类就是抽象类,不能实例化,只能被继承。派生类必须实现所有纯虚函数才能实例化,相当于强制定义接口规范。

Q:override 和 final 分别干什么?

override 让编译器检查你是否真的重写了基类虚函数,写错函数签名会直接报错,防止"以为重写了其实没有"的 bug。final 禁止派生类继续重写某个虚函数,或者禁止某个类被继承。

Q:虚函数调用比普通函数慢多少?

多一次指针间接寻址(取 vptr + 查 vtable),在现代 CPU 上通常只差几纳秒。真正的性能损失不在寻址本身,而在于虚函数调用无法被内联优化。热路径上如果频繁调用小虚函数,可以考虑 CRTP(静态多态)替代。

Q:构造函数里能调虚函数吗?

能调,但不会多态。构造函数执行时 vptr 指向的是当前正在构造的类的 vtable,不是最终派生类的。所以在基类构造函数里调虚函数,调的是基类版本,不是派生类版本。

Last Updated: 5/23/2026, 4:51:07 PM

← C++的重载和重写,以及它们的区别和实现方式 C++中的虚函数和纯虚函数有什么区别? →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪