一、多态概述
多态是面向对象编程(OOP)的一个重要特性,它允许我们使用统一的接口来处理不同类型的对象。简单来说,就是同一个操作作用于不同的对象时,可以有不同的解释和效果。在C++中,多态主要通过虚函数实现,分为静态多态(编译时多态)和动态多态(运行时多态)。
二、多态的作用
多态的主要作用是解决项目中的紧耦合问题,提供程序的可扩展性。通过多态,应用程序不必为每一个实现子类的功能调用编写单独的代码,提高了代码的复用性和可维护性。
三、多态发生的三个条件
- 有继承:子类继承自父类。
- 重写父类的虚函数:子类重写了父类中的虚函数。
- 父类指针(或引用)指向子类对象:通过父类的指针或引用来调用被重写的虚函数。
四、多态实现的原理
C++中的动态多态通过虚函数和虚函数表实现。编译器会为包含虚函数的类生成一个虚函数表(vtable),该表是一个函数指针数组,存放了类中所有虚函数的入口地址。类实例化成对象后,对象首地址处会存放一个指向虚函数表的指针(vptr)。当通过父类指针或引用调用虚函数时,会根据对象的实际类型(即运行时类型),在虚函数表中查找对应的函数指针,然后调用具体的实现代码。
五、静态多态与动态多态
-
静态多态(编译时多态):主要包括函数重载、模板和隐藏。
- 函数重载:在同一个作用域内,名称相同的函数参数类型或参数个数不同。
- 模板:编译时进行代码生成,根据传递的模板参数不同,生成不同的代码。
- 隐藏:在子类中定义与父类同名同参数的函数,隐藏了父类的同名函数。
- 动态多态(运行时多态):通过虚函数实现,即在运行时根据对象的实际类型确定调用的函数。
六、虚函数与纯虚函数
-
虚函数:用
virtual
关键字修饰的类成员函数,允许在派生类中被重写。 -
纯虚函数:没有函数体的虚函数,用于定义接口,强制派生类重写该函数。纯虚函数的一般形式为
virtual void functionName() = 0;
。
七、虚析构函数和纯虚析构函数
- 虚析构函数:当基类指针指向派生类对象时,通过基类指针删除对象时,会调用派生类的析构函数,然后调用基类的析构函数,确保对象被正确销毁。
- 纯虚析构函数:允许类成为抽象基类,强制派生类提供析构函数的实现。
八、重写、重载与重定义(隐藏)
- 重写(Override):派生类重写基类的虚函数。
- 重载(Overload):同一作用域内,函数名相同但参数类型或数量不同的函数。
- 重定义(隐藏,Name Hiding):在派生类中定义与基类同名的函数(无论参数是否相同),隐藏了基类的同名函数。
九、示例代码
#include <iostream>
using namespace std;
class People {
public:
virtual void myFunction() {
cout << "父类的虚函数" << endl;
}
virtual ~People() {} // 虚析构函数
};
class Xishi : public People {
public:
void myFunction() override { // C++11 引入 override 关键字
cout << "西施的虚函数" << endl;
}
};
void callFunction(People* p) {
p->myFunction();
}
int main() {
People* p = new Xishi();
callFunction(p); // 调用西施的虚函数
delete p;
return 0;
}