# C++构造函数与析构函数能否为虚函数
面试官问:"构造函数和析构函数可以是虚函数吗?为什么?"
这题看着基础,但很多人只能答出"构造函数不能、析构函数可以"就卡住了,说不清背后的原因——虚表指针在什么时候建立、不用虚析构会出什么问题。
# 简要回答
构造函数不能是虚函数,因为虚函数机制依赖于已构造的虚表指针,而构造期间 vptr 尚未就绪。
析构函数可以且应该是虚函数(基类场景下),确保通过基类指针删除派生类对象时能正确调用整个析构链,避免资源泄漏。
# 详细回答
| 构造函数 | 析构函数 | |
|---|---|---|
| 定义 | 与类同名,无返回类型,对象创建时自动调用 | 类名前加 ~,无参数无返回类型,对象销毁时自动调用 |
| 能否为虚函数 | 不能 | 可以,且基类应该声明为虚函数 |
| 原因 | 构造期间 vptr 尚未建立,虚函数调用机制不起作用 | 不声明为虚函数,通过基类指针 delete 派生类对象时只调用基类析构,派生类资源泄漏 |
| 调用顺序 | 基类 → 成员 → 派生类 | 派生类 → 成员 → 基类(与构造相反) |
| 特殊情况 | 构造函数内调用虚函数会静态绑定到当前类版本,不会多态 | 纯虚析构函数可以使类成为抽象类,但必须提供实现体 |
总结一下:构造时 vptr 还没准备好,所以构造函数不能虚;析构时如果不虚,多态删除就会漏掉派生类的清理。

# 知识拓展
面试官可能追问:
Q1: 什么情况下必须使用虚析构函数?
当类可能被继承,且可能通过基类指针删除派生类对象时。只要你的类设计为基类,析构函数就应该是虚的。
Q2: 构造函数中调用虚函数会怎样?
技术上能编译通过,但不会多态——只会调用当前正在构造的那个类的版本,因为此时派生类部分还没构造完,vptr 指向的是当前类的虚表。
Q3: 析构函数中抛出异常会怎样?
非常危险。如果析构是在栈展开(处理另一个异常)过程中被调用的,再抛异常会直接 std::terminate,程序终止。所以析构函数里应该吞掉所有异常。
评论
验证登录状态...