C++静态多态和动态多态

编译时多态

是指在编译阶段就能够确定要调用的函数版本,主要通过函数重载和模板(函数模板、类模板)来实现。这种多态性的实现依赖于编译器在编译时根据参数类型、数量等信息进行静态绑定(早绑定),也就是在程序运行之前就确定了具体要执行的代码逻辑。

函数重载 

在同一个作用域内,可以定义多个同名函数,只要它们的参数列表(参数个数、参数类型、参数顺序)不同即可。编译器会根据调用函数时传入的实际参数来决定调用哪一个重载版本的函数。

代码示例 

#include <iostream>
using namespace std;

// 重载函数,计算两个整数相加
int add(int a, int b) {
    return a + b;
}

// 重载函数,计算三个整数相加
int add(int a, int b, int c) {
    return a + b + c;
}

int main() {
    cout << add(1, 2) << endl;  // 调用两个整数相加的版本
    cout << add(1, 2, 3) << endl;  // 调用三个整数相加的版本
    return 0;
}

模板 

函数模板可以用来创建一个通用的函数形式,它使用模板参数来表示一些类型,在编译阶段,编译器会根据实际使用时传入的具体类型生成相应的函数实例代码。

 示例代码

#include <iostream>
using namespace std;

// 函数模板,用于交换两个变量的值
template <typename T>
void swap(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

int main() {
    int num1 = 10, num2 = 20;
    swap(num1, num2);  // 编译器根据传入的int类型,生成对应的int版本的swap函数
    cout << "num1: " << num1 << ", num2: " << num2 << endl;

    double d1 = 1.5, d2 = 2.5;
    swap(d1, d2);  // 编译器根据传入的double类型,生成对应的double版本的swap函数
    cout << "d1: " << d1 << ", d2: " << d2 << endl;
    return 0;
}

运行时多态

是指在程序运行阶段才能确定具体要调用的函数版本,在 C++ 中主要通过虚函数和继承机制来实现。它基于动态绑定(晚绑定),即当程序执行到相关代码处时,根据对象的实际类型来决定调用哪个类中的虚函数。 

虚函数与继承 

首先在基类中声明虚函数,然后在派生类中对虚函数进行重写(函数名、参数列表、返回值类型都要和基类中的虚函数匹配,且返回值类型若为指针或引用时允许协变类型)。当通过基类指针或引用指向派生类对象时,调用虚函数时会根据对象的实际类型(即派生类类型)来决定调用派生类中重写后的虚函数,而不是基类中的虚函数,这个绑定过程发生在运行时。

示例代码 

#include <iostream>
using namespace std;

class Base {
public:
    virtual void show() {  // 声明为虚函数
        cout << "Base class show function" << endl;
    }
};

class Derived : public Base {
public:
    void show() override {  // 重写基类的虚函数
        cout << "Derived class show function" << endl;
    }
};

int main() {
    Base* ptr;
    Base b;
    Derived d;

    ptr = &b;
    ptr->show();  // 调用Base类的show函数

    ptr = &d;
    ptr->show();  // 调用Derived类的show函数,因为通过基类指针指向派生类对象,运行时根据对象实际类型决定调用派生类重写后的虚函数

    return 0;
}

优缺点对比

  • 编译时多态的优点
    • 性能较好:由于函数调用在编译阶段就确定好了,不需要在运行时进行额外的类型判断等操作,所以执行效率相对较高,尤其对于对性能要求苛刻的场景(如一些实时系统中的关键代码部分)比较有利。
    • 代码可读性:函数重载等方式让代码的调用逻辑比较清晰直观,通过不同的参数形式就可以知道调用的是哪个具体功能的函数,便于代码的理解和维护。
    • 编译时错误检查:编译器能够在编译阶段检查出函数调用时参数类型等方面是否匹配正确,更早地发现错误,方便开发者及时修正。
  • 编译时多态的缺点
    • 灵活性有限:对于一些在运行时才能确定具体类型和行为的复杂情况,很难通过编译时多态来完美解决,比如根据用户输入或者程序运行中的动态配置来决定调用不同类但具有相似功能的函数。
    • 代码冗余:以函数重载为例,如果有大量功能相似但参数类型稍有不同的重载函数,代码可能会显得比较冗长,尤其是当需要修改函数的核心逻辑时,可能需要在多个重载版本中都进行修改。
  • 运行时多态的优点
    • 高度灵活:能够很好地处理在运行时对象类型不确定的情况,比如在面向对象的设计中,有一个基类表示多种具体派生类的通用行为,在程序运行时根据具体的业务逻辑生成不同派生类对象,通过运行时多态可以方便地调用相应派生类正确的重写函数,增强了程序的扩展性和可维护性。
    • 符合开闭原则:在不修改基类代码的前提下,通过在派生类中重写虚函数,可以方便地添加新的功能和行为,符合面向对象设计中开闭原则(对扩展开放,对修改封闭),便于软件系统的迭代升级。
  • 运行时多态的缺点
    • 性能开销:因为运行时需要进行动态绑定,要在内存中查找虚函数表等来确定具体调用哪个函数,相比于编译时多态会带来一定的性能损耗,在对性能要求极高且运行时类型变化不复杂的场景下可能不太合适。
    • 增加程序复杂性:虚函数、继承等机制本身就使得代码的逻辑变得相对复杂,需要开发者很好地理解面向对象中这些概念以及内存布局等相关知识,否则容易出现错误,比如虚函数重写时不小心写错函数签名导致函数没有正确重写等情况。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值