题目
理解虚函数与多态行为
信息
- 类型:问答
- 难度:⭐
考点
虚函数,多态,继承
快速回答
当通过基类指针调用虚函数时,实际执行的是对象实际类型的函数版本。代码输出为:
Dog barks
关键原因:
speak()被声明为虚函数- 通过基类指针调用
- 实际对象是派生类实例
原理说明
多态是面向对象三大特性之一,允许通过基类接口操作不同派生类对象。在C++中通过虚函数实现:
- 虚函数:使用
virtual关键字声明,在基类中定义接口 - 动态绑定:运行时根据对象实际类型确定调用的函数版本
- 虚函数表:编译器为每个含虚函数的类创建虚表,存储函数指针
代码示例分析
#include <iostream>
using namespace std;
class Animal {
public:
virtual void speak() { // 关键:虚函数声明
cout << "Animal speaks" << endl;
}
};
class Dog : public Animal {
public:
void speak() override { // 重写基类虚函数
cout << "Dog barks" << endl;
}
};
int main() {
Animal* animal = new Dog(); // 基类指针指向派生类对象
animal->speak(); // 输出取决于实际对象类型
delete animal;
return 0;
}
输出结果
程序输出:Dog barks
关键机制
- 虚函数调用流程:
- 编译器通过指针找到对象的虚表指针
- 在虚表中查找
speak()的函数地址 - 调用派生类
Dog::speak()
- 对比非虚函数:若去掉
virtual关键字,将输出Animal speaks(静态绑定)
最佳实践
- 对需要多态行为的函数始终使用
virtual关键字 - 在派生类中使用
override明确表示重写(C++11+) - 基类析构函数应声明为
virtual(本例中未展示但至关重要)
常见错误
- 忘记声明基类函数为
virtual,导致静态绑定 - 函数签名不一致(如参数不同),意外创建新函数而非重写
- 派生类函数缺少
override导致未正确重写(C++11+)
扩展知识
- final关键字:禁止派生类重写虚函数(C++11+)
- 纯虚函数:
virtual void speak() = 0;使类成为抽象类 - 动态转换:
dynamic_cast<Dog*>(animal)用于安全向下转型