多态示例。
多态
由于派生类重写基类方法,然后用基类引用指向派生类对象,调用方法时候会进行动态绑定,这就是多态。 多态分为静态多态和动态多态:
静态多态:编译器在编译期间完成的,编译器会根据实参类型来推断该调用哪个函数,如果有对应的函数,就调用,没有则在编译时报错。
动态多态:其实要实现动态多态,需要几个条件——即动态绑定条件:
虚函数。基类中必须有虚函数,在派生类中必须重写虚函数。
通过基类类型的指针或引用来调用虚函数。
说到这,得插播一条概念:重写——也就是基类中有一个虚函数,而在派生类中也要重写一个原型(返回值、名字、参数)都相同的虚函数。不过协变例外。协变是重写的特例,基类中返回值是基类类型的引用或指针,在派生类中,返回值为派生类类型的引用或指针。
函数重载:不依赖继承,解决 “同功能不同类型的调用简化”;
• 动态多态:依赖继承,解决 “基类接口与派生类实现的适配”;
• 协变:依赖继承,解决 “重写时返回值类型的灵活性问题”,是动态多态的补充。
最终目的都是在保证逻辑清晰的前提下,减少冗余代码,提升代码的可维护性和扩展性
1. 函数重载(静态多态)
特点
- 无需继承,同一类内或全局作用域中定义;
- 编译时根据参数类型自动匹配函数(静态绑定)。
代码示例
#include <iostream>
using namespace std;// 同一作用域下的函数重载(参数类型不同)
class Calculator {
public:// 重载1:int类型相加int add(int a, int b) {return a + b;}// 重载2:double类型相加(与重载1参数类型不同)double add(double a, double b) {return a + b;}
};int main() {Calculator calc;// 编译时确定调用哪个add(根据实参类型)cout << calc.add(10, 20) << endl; // 匹配int版本(输出30)cout << calc.add(3.14, 2.5) << endl; // 匹配double版本(输出5.64)return 0;
}
2. 动态多态
特点
- 依赖继承,基类需定义虚函数(
virtual
); - 派生类必须 “重写” 虚函数(函数名、参数、返回值完全相同);
- 通过基类指针 / 引用调用,运行时根据实际对象类型确定调用版本(动态绑定)。
代码示例
#include <iostream>
using namespace std;// 基类(含虚函数)
class Base {
public:// 虚函数:允许派生类重写virtual void show() {cout << "Base类的show方法" << endl;}
};// 派生类(重写基类虚函数)
class Derived : public Base {
public:// 重写:函数名、参数、返回值与基类虚函数完全一致void show() override { // override可显式标记重写(可选)cout << "Derived类的show方法" << endl;}
};int main() {Derived d; // 派生类对象Base* base_ptr = &d; // 基类指针指向派生类对象(关键条件)// 运行时动态绑定:调用派生类的show(而非基类)base_ptr->show(); // 输出:Derived类的show方法return 0;
}
3. 协变(重写特例)
特点
- 属于动态多态的特殊情况,本质是 “合法的重写”;
- 唯一区别:返回值可以不同,但必须满足 “基类返回基类指针 / 引用,派生类返回派生类指针 / 引用”。
#include <iostream>
using namespace std;// 基类
class Base {
public:// 虚函数:返回Base*virtual Base* getObject() {cout << "返回Base类对象指针" << endl;return this;}
};// 派生类
class Derived : public Base {
public:// 协变重写:返回Derived*(基类返回Base*的派生类型)Derived* getObject() override { // 符合协变规则,属于合法重写cout << "返回Derived类对象指针" << endl;return this;}
};int main() {Derived d;Base* base_ptr = &d; // 基类指针指向派生类对象// 运行时动态绑定:调用派生类的getObjectbase_ptr->getObject(); // 输出:返回Derived类对象指针return 0;
}