编程后端开发工程师 (C++)

什么是虚函数以及 C++ 中晚期绑定机制如何工作?

用 Hintsage AI 助手通过面试

答案。

问题的背景:

C++ 支持面向对象编程,这是现代语言的基础。为了实现多态性,使用了虚函数。这允许在运行时而不仅仅是在编译时调用所需的方法实现,这对具有继承结构的架构至关重要。

问题:

常见的错误是混淆静态方法调用和动态方法调用,忘记虚析构函数,错误处理继承(例如对象切片,调用基类版本而不是覆盖版本)。通常会混淆何时真正工作多态性。

解决方案:

虚函数在基类中使用关键字 virtual 声明,可以在派生类中重写(override)。如果通过指针或对基类的引用调用函数,将执行派生类中的版本。

代码示例:

struct Base { virtual void foo() { std::cout << "Base::foo "; } }; struct Derived : Base { void foo() override { std::cout << "Derived::foo "; } }; void call(Base& b) { b.foo(); } int main() { Derived d; call(d); // 输出 Derived::foo }

关键特点:

  • 晚期绑定(动态调度):方法版本的选择在运行时进行
  • 通过指针和引用访问基类
  • 正确重写函数需要关键字 override(从 C++11 开始可能)

别出心裁的问题。

通过值传递对象时多态性是否有效?

不。通过值传递导致 "切片"——只复制与参数类型相关的部分(通常是基类),多态性被关闭。

代码示例:

void call(Base b) { b.foo(); } // 总是调用 Base::foo

需要在基类中将析构函数声明为虚的吗?

是的,如果通过指向基类的指针删除派生对象。否则,会导致内存泄漏或资源未释放。

代码示例:

struct Base { virtual ~Base() {} };

如果不在子类中使用关键字 override 会发生什么?

如果在派生类中没有指定 override,但错误地更改了函数签名(例如,遗漏 const 或参数错误),则函数不会覆盖虚函数,而是创建新函数,多态性不会按预期工作。

常见错误和反模式

  • 未声明虚析构函数
  • 错误实现的 override(缺少 override,修改签名)
  • 使用值参数而非引用/指针,导致切片

实际案例

负面案例

程序员未将基类的析构函数声明为虚;通过基类指针删除对象数组导致内存泄漏。

优点:

  • 对于对象删除前的正常工作

缺点:

  • 内存泄漏,资源未释放

正面案例

声明了虚析构函数;仅使用基类型的引用/指针。多态性正常工作。

优点:

  • 内存释放的安全性
  • 干净,可扩展的代码

缺点:

  • 由于虚拟表的存在,内存和执行时间的轻微增加