什么是多态?
多态(Polymorphism)是面向对象编程的三大核心特性之一(封装、继承、多态),源于希腊语'多种形态'。在 C++ 中,它允许我们使用统一的接口处理不同类型的对象,显著提高了代码的灵活性和可扩展性。
核心概念
- 同一接口,多种形态:不同的对象可以通过相同的方法名调用,但实际执行的逻辑由对象自身的类决定。
- 解耦调用与实现:调用者只需关注接口(方法名和参数),无需关心具体实现,提高代码的可扩展性和可维护性。
多态的定义及实现
多态的构成条件
多态是一个继承关系下的类对象,去调用同一函数,产生了不同的行为。实现多态还有两个必须重要条件:
- 必须是基类的指针或者引用调用虚函数。
- 被调用的函数必须是虚函数,并且完成了虚函数重写/覆盖。
说明:要实现多态效果,第一必须是基类的指针或引用,因为只有基类的指针或引用才能既指向基类对象又指向派生类对象;第二派生类必须对基类的虚函数完成重写/覆盖,重写或者覆盖了,基类和派生类之间才能有不同的函数,多态的不同形态效果才能达到。
虚函数
类成员函数前面加 virtual 修饰,那么这个成员函数被称为虚函数。注意非成员函数不能加 virtual 修饰。
class A {
public:
virtual void func() {}
};
虚函数的重写/覆盖
虚函数的重写/覆盖:派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称派生类的虚函数重写了基类的虚函数。
注意:在重写基类虚函数时,派生类的虚函数在不加 virtual 关键字时,也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性)。
关键技术原理
- 虚函数表(vtable)
- 每个包含虚函数的类自动生成虚函数表
- 存储该类所有虚函数的地址
- 创建对象时隐式添加 vptr 指针指向 vtable
- 动态绑定过程:基类指针查询对象 vptr 访问 vtable 调用实际函数地址
最佳实践指南
- 使用 override 关键字明确重写意图
- 基类析构函数必须声明为 virtual
- 接口类使用纯虚函数
- 性能考量:虚函数调用比普通函数多一次指针解引用
虚函数重写
协变
派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。
核心概念
- 基类虚函数返回基类类型指针 / 引用。
- 派生类重写函数返回派生类类型指针 / 引用。
- 编译器会自动处理类型转换,确保调用的一致性。
协变的条件
- 基类函数必须为虚函数。
- 返回类型必须是指针或引用(不能是值类型)。
- 派生类返回类型必须是基类返回类型的公有派生类。
- 函数签名的其他部分(参数、常量性)必须完全相同。
析构函数的重写
基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加 virtual 关键字,都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同看起来不符合重写的规则,实际上编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成 destructor,所以基类的析构函数加了 virtual 修饰,派生类的析构函数就构成重写。


