火龙信奥
  • 首页
  • 课程
  • 题库
  • 打卡
    • 代码对战
    • 快速对战
  • 题单
  • 团队
  • 荣誉墙
  • 商城
  • 登录 / 注册

C++多态性

作者: 作者的头像   huolong , 时间:2026-03-21 12:16:34 , 所有人可见, 阅读  12

一、多态的概念 多态的概念就是:就是有多种形态,在C++中多态分为编译时多态(静态多态)和运行时多态(动态多态)。

编译时多态就是我们的函数重载和模板了,就比如我们使用cout函数的时候,前面我们将的时候是说其会自动去识别要打印的数据的数据类型 ,但是实际上其也是一种多态。

其实际上是去调用的operator <<,然后其根据数据的类型去匹配调用。

可以看到我们使用cout打印两个不同的数据类型,其在编译的时候实际上是使用的不同的函数。

编译时多态其是通过我们传入的数据的参数就可以调用不同的函数,其通过参数的类型和数量来判断,其称为编译时多态的原因是因为其是在实参传给形参的时候的参数匹配是在编译阶段完成的,我们一般是将编译时的多态称为静态多态,在运行的时候归为动态。

运行时多态,其是指完成某个行为,其可以传不同的对象来进行这个行为,然后这个对象对这个行为最后产生的结果会有影响。就比如我们大学生最熟悉的在买回家和上学的高铁火车票的时候,我们选择乘车人的时候,其会弹出一个窗口让我们选择买学生票还是成人票,然后我们选择学生票的话,那么就会有打折。

二、多态的实现 首先多态是一个继承关系下的类对象,其去调用同一个函数,但是形成的结果是不一样的。 然后我们实现多态必须要满足下面的两个条件: 1、必须是基类的指针或者引用调用虚函数

2、被调用的函数必须是虚函数,而且完成了函数的重写/覆盖

那么啥是虚函数呢?

类中的成员函数的前面使用virtual关键字进行修饰,那么这个函数就是虚函数了。不过要注意的是非成员函数不要加virtual进行修饰。

如上使用virtual修饰即可。

虚函数是多态实现的关键,我们知道函数的重载在C语言中是不允许的,在C++中其运行派生类重写基类,然后其会在运行的时候根据调用的对象来决定使用的函数。

那么虚函数是如何进行重写的呢?

虚函数的重写指的是拍生类中有一个函数和基类中完全相同的虚函数。要注意的是:相同的是函数的返回值类型、函数名、参数列表。那么就说派生类中的虚函数重写了基类中的须函数。

然后我们要注意的是在重写基类虚函数的时候,派生类的虚函数是可以不使用virtual修饰的,这样也可以构成重写,但是这种写法不是很规范,我们建议还是都写上。

不过可能会有题目这么来考:

题目:以下程序输出结果是什么?

选项: A:A->0 B:B->1 C:A->1 D:B->0 E:编译出错 F:以上都不正确

#include <iostream>
using namespace std;

class A {
public:
    virtual void func(int val = 1) { 
        std::cout << "A->" << val << std::endl; 
    }
    virtual void test() { 
        func(); 
    }
};

class B : public A {
public:
    void func(int val = 0) { 
        std::cout << "B->" << val << std::endl; 
    }
};

int main(int argc, char* argv[]) {
    B* p = new B;
    p->test();
    return 0;
}

我们看看上面的代码,首先在编译的时候,派生类会先在自己的成员函数中找是否有这个函数,然后再去基类中寻找,那么我们上面的代码中其先调用test函数,那么我们的派生类中没有,那么就去基类中寻找,那么我们在基类中的test函数的内容是调用func函数,但是我们发现func函数是虚函数,而且在派生类中有重写,那么就构成多态了,那么其就还是调用的自己类域中的函数,说到这里我们有的同学就会去选择答案D了,但是还有一点要注意的是,我们的多态是将函数的内容重写而已,对于函数的返回值类型,函数名,函数的参数列表是不动的,那么我们的缺省值使用的是基类中的,所以我们对于多态的重写我们可以理解为只对后面大括号的内容进行改变。

所以我们这道题的答案应该为B选项。

析构函数的重写:

我们先看下面一段代码: 我们发现在调用p2的析构的时候,其是先调用的派生类的析构函数,然后再调用的基类的析构函数,这说明基类的析构函数和派生类的析构函数是构成多态的,但是我们知道基类和派生类的函数名是不可能相同的,这两个函数在构成多态的要求上是不满足的,而且我们的基类中的析构函数也没有使用virtual修饰。这是为什么呢?

这是因为编译器会对继承中的析构函数进行特殊处理了,处理成destructor(),即~A()和~B()都被处理成了destructor(),那么这样就达到我们多态的要求了。

要是不构成多态的话,我们上面的程序就会造成内存泄漏,这是因为要是不构成多态那么就只会调用A中的析构,那么派生类中的内存空间就没有被释放了。

override和final:

我们在对函数进行重写的时候,可能会因为一些操作的失误,导致没有构成重写,就比如我们的函数名字是很长的,那么难免会写错一些单词啥的,还有就是参数列表中参数可能也会弄错,而且我们的这种错误在编译的时候是不会报错的,那么在C++11 中提供了关键字override,这个关键字可以帮助用户检测虚函数是否构成重写。

然后要是我们不想让派生类去重写这个函数,那么我们可以使用关键字final进行修饰

纯虚函数和抽象类:

我们在虚函数的后面写=0,那么这个函数就是纯虚函数了,然后纯函数是不需要被定义的。这是因为其被定义了也没意义,其是必须要被派生类重写的,所以只需要声明即可。

然后包含了纯虚函数的类叫做抽象类,然后抽象类是不可以实例化出对象的,然后要是派生类继承后,不重写纯虚函数的话,那么派生类也是抽象类。纯虚函数某种程度上强制了派生类必须重写虚函数,因为要是不写就不能实例化出对象。

下面是重载/重写/隐藏对比:

—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com

©2026加盟我们 | 关于我们 | ACM课程 | 常见问题 | 成果墙 | 评测记录 | 浙ICP备2021013995号
在线画图 | OI WIki | 打字练习
火龙信奥
请输入登录信息


请完成安全验证
验证码底图 滑块
向右拖动滑块完成验证
请输入用户名 / 绑定的手机号码



请输入注册信息(手机号验证码注册)





验证码5分钟有效,60秒内不可重复获取,每日最多3次

微信登录

微信登录二维码

正在生成二维码...

账号已过期,请续期。
去续期

绑定手机号

📱

为了更好地保护您的账号安全,享受完整的平台服务

请您尽快绑定手机号码