C++ 多态的定义及实现

2023-10-27

C++ 多态的定义及实现

1. 多态定义的构成条件

多态是在不同继承关系的类对象,去调同一函数,产生了不同的行为。

就是说,有一对继承关系的两个类,这两个类里面都有一个函数且名字、参数、返回值均相同,然后我们通过调用函数来实现不同类对象完成不同的事件。

但是构成多态还有两个条件:

  1. 调用函数的对象必须是指针或者引用。
  2. 被调用的函数必须是虚函数,且完成了虚函数的重写。

说了这么多,怎么实现呢?我们先来看一段代码。

#include <iostream>

class Person 
{
public:
    virtual void BuyTicket(int)
    {   
        std::cout << "Adult need Full Fare!" << std::endl;
    }   
};

class Child : public Person
{
public:
    virtual void BuyTicket(int)
    {   
        std::cout << "Child Free!" << std::endl;
    }   
};

void fun(Person& obj)
{
    obj.BuyTicket(1);                                                                                                                             
}

int main(void)
{
    Person p;
    Child c;

    fun(p);
    fun(c);

    return 0;
}

在这里插入图片描述

  1. 调用函数就是这里的fun,参数int没有实际意义,就是为了体现函数重写必须要返回值一样、函数名一样和参数一样。
  2. 被调用的函数必须是虚函数,也就是说必须要在两个产生多态的函数前面加virtual关键字
  3. 调用函数的形参对象必须是基类对象,这里是因为派生类只能给基类赋值,会发生切片操作。基类不能给派生类赋值。
  4. 调用函数的参数必须是指针或引用,因为派生类改变了虚表,那么这个虚表就属于派生类对象,赋值的时候只会把基类的成员给过去,虚表指针不会给。所以在调用函数的时候会发生语法检查,如果满足多态的条件,就会触发寻找虚表中虚函数地址。如果不满足条件,则会直接用基类对象调用基类函数。

上面牵扯出两个概念:

  1. 虚函数:虚函数就是在类的成员函数前面加virtual关键字。

  2. 虚函数重写:虚函数的重写:派生类中有一个跟基类的完全相同虚函数,我们就称子类的虚函数重写了基类的虚函数。

    完全相同是指:函数名、参数、返回值都相同。另外虚函数的重写也叫作虚函数的覆盖

    虚函数重写有一个例外错误:协变

    重写的虚函数的返回值可以不同,但是必须分别是基类指针或引用和派生类指针或引用。

    这种情况在VS会报错,但是在linuxG++下不会

    #include <iostream>
      
    class A                                                                  
    { 
    public:                                                                  
        virtual A* fun()
        {
            return new A;                                                    
        }
    };
    
    class B : public A
    {
    public:
        virtual B* fun()
        {
            return new B;
        }
    };
    

不规范重写行为:

就是在派生类的重写函数加了virtual关键字,但是在派生类的重写函数前不加。

这样不会报错,因为继承的原因,将这个virtual的性质继承了下来,但是这样写不规范,

如果两个函数构成重写,那么要在两个函数前都加上virtual关键字。

2.析构函数重写问题

基类中的析构函数如果是虚函数,那么派生类的析构函数就重写了基类的析构函数。这里他们的函数名不相同,看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor,这也说明的基类的析构函数最好写成虚函数。

将析构函数定义为虚函数的原因:

因为基类指针可能指向派生类,当delete的时候,如果不定为虚函数,系统会直接调用基类的析构函数,这个时候派生类就有一部分没有被释放,就会造成可怕的内存泄漏问题。

若定义为虚函数构成多态,那么就会先调用派生类的析构函数然后派生类的析构函数会自动调用基类的析构函数,这个结果满足我们的本意。

所以!在继承的时候,尽量把基类的析构函数定义为虚函数,这样继承下去的派生类的析构函数也会被变成虚函数构成多态。

3.抽象类

在虚函数的后面写上 =0 ,则这个函数就变成纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。

这个纯虚函数的作用就是强迫我们重写虚函数,构成多态。这样更加体现出了接口继承。

#include <iostream>

class Person
{
public:
    virtual void Strength() = 0;
};

class Adult : public Person
{
public:
    virtual void Strength()
    {   
        std::cout << "Adult have big Strength!" << std::endl;
    }   
};

class Child : public Person
{
public:
    virtual void Strength()
    {   
        std::cout << "Child have Small Strength!" << std::endl;                                                                                   
    }   
};

4.C++11 override 和 final

override:

override是用来检查函数是否重写,是在virtual void fun() override {}这里加上,然后来检查的。实际中,建议这样写。

final:

final是在class A final {};这里加上,目的是为了不让这个类被继承。
或者,在一个函数后加,表示这个函数不能被重写。void fun() final {}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 多态的定义及实现 的相关文章

随机推荐

  • QT中 No such file or directory的解决办法

    报错具体情境 使用D Qt Qt5 8 0 5 8 mingw53 32 gt 终端进行编译程序 步骤如下 qmake project 生成CH01 pro 文件 qmake CH01 pro 生成 Makefile 总的makefile
  • 【Hadoop生态圈】8.Flink实时计算引擎入门教程

    文章目录 1 简介 2 执行流程 3 核心三大组件 4 应用场景 5 架构原理 6 常用的API 7 java编写flink程序 8 把flink程序部署到hadoop环境上面运行 8 1 安装flink程序 8 2 编译java开发的fl
  • QTcpSocket 及 TCP粘包分析

    http blog csdn net u011125673 article details 50474741
  • Maven实战(二)构建简单Maven项目

    上一节讲了maven的安装和配置 这一节我们来学习一下创建一个简单的Maven项目 1 用Maven 命令创建一个简单的Maven项目 在cmd中运行如下命令 mvn archetype generate DgroupId com myco
  • obj生成到不同目录下

    2 down vote use Configuration Properties gt C C gt Ouptut Files gt IntDir RelativeDir Filename this will duplicate the s
  • 下载视频并保存至手机相册

    功能介绍 需要将转码后的视频 小于20MB 通过APP下载至手机相册 可以将小视频分享至微信传播 1 通过服务器转码视频 或者很多云服务商都会提供这个功能 2 通过APP下载至手机相册 这个是咱们需要做的事 主要技术 用到 URLSessi
  • 模型训练测试之一:ScaledYOLOv4

    Scaled YOLOv4 YOLOv4官方改进版 55 8 AP 很新 我就测下 Github地址 Gitee 地址 推荐 新的改变 聚焦于针对 YOLOv4 的模型缩放 model scale 旗下有三款模型 YOLOv4 CSP 面向
  • 74LS138译码器真值表以及快速计算方法

    74LS138真值表以及快速计算方法 掌握了74LS138译码器的快速计算的方法 就能够在使用74LS138译码器的时候 不用老是去查阅译码器的真值表的对应关系 74LS138译码器真值表 快速计算方法 将输入端的A B C看作成3位的二进
  • 依分布收敛的定义细节

    1 定义 依分布收敛的定义是这样的 随机变量序列 X n n 1 X n n 1 infty Xn n 1 若它们的累积分布函数cdf序列 F n n 1 F n n 1 infty Fn n 1 与某个随机变量 X X X的cdf F F
  • 解决论文写作排版中,两端对齐导致文字间距被word补过大的问题

    在段落中 中英文参杂 设置两端对齐 导致中英文的文字间距被word拉的过大 解决方法 选中修改的段落 这样设置就行
  • mac系统终端运行python文件

    1 在要运行的python文件首行里添加python解释器路径代码 代码 usr bin env python3 注意 上面代码中的python3是对应当前的python版本 例子 2 复制要运行的python文件位置 在终端使用代码进入要
  • 深入理解js——函数和对象的关系

    函数也是对象 但是函数却不像数组 数组是对象的一种 它是对象的一个子集 函数和数组之间不是单纯的包含与被包含的关系 它们之间有点像鸡生蛋蛋生鸡的逻辑 来例子 function Fn this name 小明 this age 10 var
  • (java基础知识)HashMap排序,Comparator接口详解

    对于List 可以调用Collections工具类的sort 方法 直接进行排序 HashMap 就没这么幸福了 其实 只要了解了Comparator这个接口之后 HashMap的排序也就不难了 无论是根据key 还是根据value排序 这
  • Ant Design Pro 2.0前端配置服务器代理,不使用mock数据

    在config js文件中可找到注释掉的 proxy server api target https preview pro ant design changeOrigin true pathRewrite server 取消注释 然后 p
  • vue + element实现el-date-picker的时间格式转换,以及自定义时间格式,修改输入的时间格式

    使用vue2 elementUi实现日期选择输入框的时间格式转换 根据数据的情况自动化格式为需要的格式 如果只是需要修改传给后端的值或者格式 可以使用 value format实现 可以在文档上查看详细的介绍
  • 强化学习——动态规划法

    文章目录 前言 一 动态规划法简单认识 1 基本概念 2 适用情况 3 求解步骤 4 典型案例 二 值函数 1 累计折扣奖励 2 状态值函数 3 动作值函数 4 状态值函数与动作值函数的关系 5 贝尔曼方程 动态规划法核心 三 策略评估 1
  • 学生信息管理系统测试总报告

    目录 1 前言 4 1 1 编写目的 4 1 2 背景说明 4 1 3 适用范围 4 1 4 参考资料 4 2 实验设备与软件环境 4 3 测试需求 5 3 1 需求分析 5 3 2 功能需求 5 3 2 1 系统管理模块 6 3 2 2
  • npm 常见命令 安装 卸载 查看版本

    npm 常见命令 安装 卸载 查看版本 npm list 查看本地已安装模块清单 npm list packageName 查看本地已安装模块版本 npm info packageName 查看模块的详细信息 包括各版本号等 npm vie
  • kcf跟踪算法实例整理

    http blog csdn NET shenxiaolu1984 article details 50905283 本文的跟踪方法效果甚好 速度奇高 思想和实现均十分简洁 其中利用循环矩阵进行快速计算的方法尤其值得学习 另外 作者在主页上
  • C++ 多态的定义及实现

    C 多态的定义及实现 1 多态定义的构成条件 多态是在不同继承关系的类对象 去调同一函数 产生了不同的行为 就是说 有一对继承关系的两个类 这两个类里面都有一个函数且名字 参数 返回值均相同 然后我们通过调用函数来实现不同类对象完成不同的事