卡码笔记
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
  • 基础与语法

  • 面向对象

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

  • 内存管理

  • C++11 与现代 C++

  • 智能指针

  • 并发与 I/O

# 虚函数怎么实现的?

# 简要回答

虚函数通过“虚函数表”(vtable)实现,编译器为含有虚函数的类生成一个虚表(vtable),类对象中包含一个虚指针(vptr)指向该表,即虚表。

通过虚表实现运行时的动态绑定,从而支持多态。

# 详细回答

虚函数的实现机制如下: 第一,虚函数表(vtable):每个类有一个虚表,存储该类的虚函数地址列表。

如果某个类有虚函数,编译器就会自动生成这张表。

第二,虚指针(vptr): 每个含虚函数的类对象都有一个隐藏的成员,叫虚指针,指向当前类的虚表,这个指针用于运行时确定函数的真实调用目标。

第三,调用过程: 当通过基类指针或引用调用一个虚函数时,程序会:

先找到对象里的 vptr;

然后根据 vptr 找到对应类的 vtable;

再从 vtable 中取出正确的函数地址并调用它。

第四,动态绑定(多态): 这种通过虚表间接调用函数的方式,就是运行时多态。它让程序在运行时决定调用哪个类的函数,而不是编译时决定。

# 代码示例

#include <iostream>
using namespace std;

class Base {
public:
    virtual void show() {
        cout << "Base::show()" << endl;
    }
};

class Derived : public Base {
public:
    void show() override {
        cout << "Derived::show()" << endl;
    }
};

int main() {
    Base* b = new Derived();
    b->show();  // 输出:Derived::show()
    return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

创建 Derived 对象时,它的 vptr 指向 Derived 类的虚表。

当执行 b->show(),实际运行的是 Derived::show(),这是通过 vptr → vtable 间接跳转实现的。

# 知识拓展

  • 试试图解

image

非虚函数调用过程:编译器在编译时就决定调用哪个函数(静态绑定),效率高,但无法实现多态。

虚析构函数:当通过基类指针删除派生类对象时,基类析构函数必须是虚函数,否则不会调用派生类析构函数,可能导致资源泄露。

  • 面试官可能追问

vtable 和 vptr 的内存布局是怎样的?

答:vptr 通常是放在对象内存布局的 第一个位置,这样通过对象首地址就能快速访问虚函数表。

多继承时,一个对象可能有 多个 vptr(每个继承链一个),对应多个 vtable。

虚函数和普通函数在调用开销上的不同?

答:虚函数和普通函数在调用机制上的最大区别在于绑定时机和调用方式;

普通函数是在编译时就完成绑定,调用时直接跳转到函数地址,效率较高;

而虚函数是在运行时通过对象中的虚指针(vptr)查找对应的虚函数表(vtable),再从表中找到目标函数地址进行调用,这种多了一次间接寻址的过程导致其调用开销相对较大。

不过,正因为虚函数采用动态绑定,才支持运行时多态,而普通函数不具备这种能力。

简单来说,虚函数的灵活性是以一点性能损耗为代价换来的。

Last Updated: 3/10/2026, 6:08:48 PM

← C++中的虚函数和纯虚函数有什么区别? 虚函数表是什么 →

评论

验证登录状态...

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