C++面试高频:多态与虚函数
大家在准备 C++ 面试时,多态与虚函数也是一个绕不过去的高频考点。
它不只是知道概念这么简单,面试官更常问的是:
什么是多态
虚函数是怎么实现的
vtable 和 vptr 是什么
override 有什么作用
纯虚函数和抽象类是什么
为什么基类析构函数一般要写成 virtual
构造函数和析构函数里调用虚函数会发生什么
这篇文章就把多态、虚函数、vtable、vptr、override、纯虚函数、抽象类这些高频点系统梳理一遍,适合面试前快速过一遍。
一 什么是多态
多态,简单理解就是:
同样的函数调用,因为对象实际类型不同,表现出不同的行为。
比如都调用draw():
如果对象是圆形,就画圆
如果对象是矩形,就画矩形
这就是多态。
在 C++ 里,多态主要分两类:
1 编译时多态
也叫静态多态,常见形式有:
函数重载
运算符重载
模板
它在编译阶段就已经确定要调用哪个函数。
2 运行时多态
也叫动态多态,主要依靠:
继承
虚函数
基类指针或引用调用派生类对象
面试里通常说的“多态”,大多指的就是运行时多态。
面试怎么说
可以直接回答:
多态就是同一个接口在不同对象上表现出不同的行为。
C++ 里分编译时多态和运行时多态,面试里常说的多态一般指运行时多态,它通过虚函数配合继承和基类指针/引用来实现。
二 运行时多态成立的条件
不是只要有继承就一定有多态,运行时多态成立一般要满足三个条件:
1 存在继承关系
派生类继承基类。
2 基类函数被声明为 virtual
代表这个函数是虚函数。
3 通过基类指针或基类引用调用
这是最容易被忽略的点。
看代码:
#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() { Derived d; Base* p = &d; p->show(); // 输出 Derived::show return 0; }这里就是典型的运行时多态。
易错点
如果不是通过基类指针/引用调用,而是直接对象调用,那就不是这里说的运行时多态。
比如:
Derived d; d.show();这只是普通成员函数调用。
面试怎么说
可以直接背:
运行时多态的条件一般是三点:有继承、有虚函数、通过基类指针或引用调用派生类对象。少一个,通常都不能形成真正的运行时多态。
三 什么是虚函数
虚函数就是在基类中用virtual修饰的成员函数。
它的作用是:
允许派生类重写这个函数,并在通过基类指针或引用调用时,运行时决定到底执行基类版本还是派生类版本。
示例:
#include <iostream> using namespace std; class Animal { public: virtual void speak() { cout << "Animal speak" << endl; } }; class Dog : public Animal { p