【C++】多态概念(入门)

介绍:

        多态的概念:通俗来说,多态就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。比如扫红包操作,同样是扫码动作,不同的用户扫 得到的不一样的红包,这就是一种多态行为。

多态的构成条件

        首先,我们先来认识一下虚函数。在类中,被virtual修饰的类成员函数称为虚函数。如下;

class Person {
public:
    virtual void BuyTicket()  //虚函数

    {

        cout << "买票-全价" << endl;

    }
};

        多态的构成需要两个条件:1,必须通过基类的指针或者引用调用虚函数,这时传入的是父类调用的是父类虚函数,传入的是子类调用的是子类的虚函数。2,被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写(重写:派生类中有一个跟基类完全相同的虚函数,即派生类虚函数与基类虚函数的 返回值类型、函数名字、参数列表完全相同,称子类的虚函数重写了基类的虚函数)。

        注意:多态中,派生类的virtual写不写都可以,但是基类的virtual必须写上。

#include <iostream>
using namespace std;
class Person 
{
public:
    virtual void BuyTicket() 
    {
        cout << "买票-全价" << endl; 
    }
};
class Student : public Person 
{
public:
    virtual void BuyTicket() 
    {
        cout << "买票-半价" << endl;
    }
    /*注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用,如以下*/
   /*void BuyTicket() { cout << "买票-半价" << endl; }*/

   //注意:基类无论在什么情况下若不加virtual就无法构成重写,也就说基类必须写上virtual
};
void Func(Person& p)  //通过基类Person引用调用虚函数
{
    p.BuyTicket();
}
void Func2(Person p)  
{
    p.BuyTicket();
}
int main()
{
    Person ps;
    Student st;
    Func(ps);
    Func(st);
    cout << endl;
    //下面的调用将全部调用基类的函数
    Func2(ps);
    Func2(st); 
    return 0;
}

        总的来说在继承体系中存在两种调用:普通调用和多态调用

                普通调用:系统看的是指针或引用或对象本身的类型。   

                多态调用:系统看的是具体指向的对象。

虚函数重写的两个例外

1,协变:基类与派生类虚函数返回值类型不同,但这里返回值必须要求是父子类关系的指针或引用。(协变本身没有意义,这里只需了解即可)

#include <iostream>
using namespace std;
class A 
{    };
class B : public A
{    };
class Person {
public:
    virtual A* f() {
        cout << "Person A::f()" << endl;
        return new A; 
    }
    void fun()
    {
        cout << "class Person" << endl;
    }
};
class Student : public Person {
public:
    virtual B* f() {
        cout << "Student B::f()" << endl;
        return new B;
    }
    void fun()
    {
        cout << "class Student" << endl;
    }
};

int main()
{
    Person* p = new Student; 
    p->f(); //调用子类Student函数,即多态协变
    p->fun();  //调用父类Person函数,即继承赋值转换,不是隐藏
    Person p1;
    Student s;
    p1 = s;
    p1.fun();  //同理,调用父类Person函数
    return 0;
}

2. 析构函数的重写(基类与派生类析构函数的名字不同)

        继承体系中,基类与派生类的析构函数中存在问题。比如当我们使用基类指针指向派生类地址空间时,由于指针指向的是派生类中基类的地址,所以这里结束时默认调用基类析构函数,不会调用派生类析构函数,这将会导致派生类中部分空间没有释放,导致内存泄漏问题。因此,这里需使用虚函数,使其调用派生类的析构函数。

        如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字, 都与基类的析构函数构成重写,这里是特殊情况,这里可以理解为编译器对析构函数的名称做了特殊处理。

#include <iostream>
using namespace std;
class Person {
public:
    virtual ~Person() { 
        cout << "~Person()" << endl;
    }
};
class Student : public Person {
public:
     virtual ~Student() { 
        cout << "~Student()" << endl;
    }
};

int main()
{
    // 析构函数在没有加virtual关键字前,下面的两次清理空间都调用Person的析构函数。
    Person* p1 = new Person;
    delete p1;
    //在没有加上virtual前,开辟派生类Student空间中的析构函数没有调用,即派生类中部分空间没有清理,可能会导致内存泄漏
    //加上virtual后,将会调用指向对象的析构函数,即子类Student的析构函数,之后会调用基类Person的析构函数

    Person* p2 = new Student; 
    delete p2;
    return 0;
}

C++11标准的override和final

1,final:它即可修饰虚函数,表示该虚函数不能再被重写,也可修饰类,表示此类不能被继承

#include <iostream>
using namespace std;

class A final
{
public:
    A()
    {    }
};
class B : public A //直接报错,final修饰的类不可被继承
{
public:
    B()
    {    }
};

class A
{
public:
    virtual void Drive() final 
    {    }
};
class B : public A
{
public:
    virtual void Drive() { //基类Drive虚函数加上final,不能被重写
        cout << "B" << endl;
    }
};

        说到这里,要想父类不被子类继承,除了使用final关键字外,只需将父类的构造函数私有化,使子类实例不出对象即可。

class A
{
private:
    A()
    {    }
};
class B : public A
{
public:
    B()  //在子类B中不能调用父类A的构造函数,即不能被继承
    {    } 
};

2,override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。此关键字通常用来检查重写有没有问题。

#include <iostream>
using namespace std;
class A {
public:
    virtual void Drive() 
    {    }
    void test()
    {    }
};
class B : public A {
public:
    virtual void Drive() override { 
        cout << "B" << endl;
    }
    virtual void test() override { //没有重写基类虚函数,报错

    }
};
int main()
{
    A a;
    B b;
    return 0;
}

        最后,我们总结重载、重写和隐藏。三者关系非常紧密,如下图:

        在多态中,这里还有很多注意点,我们先以下面代码的典型例子来分析多态的运用。

#include <iostream>
using namespace std;
class A
{
public:
    virtual void func(int val = 1) { 
        cout << "A->" << val << endl;
    }
    virtual void test() { 
        func();  //这里通过this指针调用func,但这里属于多态调用,指向是对象是子类,所以会调用子类func
        //注意:val的数值为1是因为这里可看成基类声明func,子类定义func

    }
};
class B : public A
{
public:
    void func(int val = 0) {
        cout << "B->" << val << endl; 
    }
};
int main()
{
    B* p = new B;
    B b;
    //下面两次都输出B->1
    b.test(); 
    p->test();
    return 0;
}

         我们知道,在重写中,只要派生类写上virtual,基类可不用写virtual,这是因为virtual关键字的主要目的是在基类中标记一个函数,以便在派生类中可以重写它以实现多态性。在以上代码逻辑中,这里可看成基类实现虚函数的声明,派生类实现虚函数的定义。因此val的数值为1。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/263774.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

限流算法

下面对常见的限流算法进行讨论。目前&#xff0c;常用的限流算法主要有三种&#xff1a;计数器法、滑动窗口算法、漏桶算法和令牌桶算法。下面分别介绍其原理。 1. 计数器法 计数器法是通过计数对到来的请求进行选择性处理。如系统限制一秒内最多有X个请求&#xff0c;则在该…

042 继承

代码实现 首先定义Person类&#xff08;人类&#xff09; /*** 人的基础特征** author Admin*/ public class Person {/*** 姓名*/String name;/*** 生日*/Date birthday;/*** 手机号码*/String tel;/*** 身份证号码*/String idCode;public Person() {}public Person(String …

关于添加第三方jar包到SpringBoot工程中的一些问题

1&#xff1a;如果是多级module工程的情况下&#xff0c;将jar包添加到当前module中&#xff1b; 2&#xff1a;在当前需要依赖的maven工程中添加 外部jar包路径进行引入 <dependency><groupId>kuaishou</groupId><artifactId>kuaishou-merchant-ope…

自定义悬浮气泡组件

一.常用悬浮气泡展示 在一个项目中&#xff0c;常常会使用点悬浮展示&#xff0c;而市面上悬浮tooltip的组件非常多 例如常用的antd提供的Tooltip 用法如下&#xff08;来自于官方文档示例&#xff09;&#xff1a; import React from react; import { Button, Tooltip, Con…

FariyGUI × Cocos Creator 3.x 弹窗制作

在fgui里制作一个弹窗 新建一个按钮&#xff0c;作为返回按钮 新建一个标签 做成这个样子 其中包含两个节点&#xff0c;名称分别为title和closeButton 可以阅读fgui的源码window.js得到&#xff0c;closeButton按钮只需要输入名称即可在contentPane设置时自动绑定。 且会…

计算机网络-网络互联与互联网(一)

1.常用网络互联设备&#xff1a; 1层物理层&#xff1a;中继器、集线器2层链路层&#xff1a;网桥、交换机3层网络层&#xff1a;路由器、三层交换机4层以上高层&#xff1a;网关 2.网络互联设备&#xff1a; 中继器Repeater、集线器Hub&#xff08;又叫多端口中继器&#xf…

Git笔记——4

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、操作标签 二、推送标签 三、多人协作一 完成准备工作 协作开发 将内容合并进master 四、多人协作二 协作开发 将内容合并进master 五、解决 git branch -a…

【论文解读】transformer小目标检测综述

目录 一、简要介绍 二、研究背景 三、用于小目标检测的transformer 3.1 Object Representation 3.2 Fast Attention for High-Resolution or Multi-Scale Feature Maps 3.3 Fully Transformer-Based Detectors 3.4 Architecture and Block Modifications 3.6 Improved …

直接写就行!EI顶刊组合:多能源微网/综合能源系统两阶段鲁棒优化配置方法代码!

适用平台&#xff1a;MatlabYalmipCplex 参考文献&#xff1a; 《考虑机组禁止运行区间的含风电鲁棒机组组合》-中国电机工程学报 《微电网两阶段鲁棒优化经济调度方法》-中国电机工程学报 程序提出了微电网中电源容量的两阶段鲁棒优化配置模型&#xff0c;第一阶段主要决策…

初识51单片机

##江科大51单片机学习 什么是单片机&#xff1f;&#xff1f;&#xff1f; 单片机&#xff0c;英文名&#xff0c;Micro Controller Unit&#xff0c;简称MCU&#xff08;tips&#xff1a;有人会简称它为CPU&#xff0c;但不是如此&#xff0c;CPU其实被集成在MCU中&#xff…

Tomcat 学习之 Servlet

目录 1 Servlet 介绍 2 创建一个 Servlet 3 web.xml 介绍&#xff08;不涉及 filter 和 listener 标签&#xff09; 3.1 display-name 3.2 welcome-file-list 3.3 servlet 3.4 session-config 3.5 error-page 3.6 context-param 4 ServletContext 5 ServletConfig …

前后端分离vue.js+nodejs学生考勤请假系统 _fbo36

此系统设计主要采用的是nodejs语言来进行开发&#xff0c;采用vue框架技术&#xff0c;框架分为三层&#xff0c;分别是控制层Controller&#xff0c;业务处理层Service&#xff0c;持久层dao&#xff0c;能够采用多层次管理开发&#xff0c;对于各个模块设计制作有一定的安全性…

解决easyExcel模板填充时转义字符\{xxx\}失效

正常我们在使用easyExcel进行模板填充时&#xff0c;定义的变量会填充好对应的实际数据&#xff0c;未定义的变量会被清空&#xff0c;但是如果这个未定义的变量其实是模板的一部分&#xff0c;那么清空了就出错了。 在这张图里&#xff0c;上面的是模板填充后导出的文件&…

探索无限维度的奥秘:Hilbert空间

当我们提到空间&#xff0c;你可能会立即想到周遭的环境——三维世界&#xff0c;其中事物可以向上或向下、左或右、前或后移动。然而&#xff0c;在数学和物理学的世界里&#xff0c;有一种抽象的空间概念&#xff0c;它不仅覆盖了我们的三维空间&#xff0c;还包括了更复杂的…

【Java程序设计】【C00313】基于Springboot的物业管理系统(有论文)

基于Springboot的物业管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的物业管理系统&#xff0c;本系统有管理员、物业、业主以及维修员四种角色权限&#xff1b; 管理员进入主页面&#xff0c;主要功能包…

MATLAB 导出可编辑的eps格式图像

任务描述&#xff1a;部分期刊要求提交可编辑的eps格式图像&#xff0c;方便美工编辑对图像进行美化 我试了直接print或者在figure窗口导出&#xff0c;发现导出的文件放到Adobe AI中并不能编辑&#xff0c;经Google找到解决办法&#xff1a; %EPS exportgraphics(gcf,myVect…

jQuery瀑布流画廊,瀑布流动态加载

jQuery瀑布流画廊&#xff0c;瀑布流动态加载 效果展示 手机布局 jQuery瀑布流动态加载 HTML代码片段 <!-- mediabanner --><div class"mediabanner"><img src"img/mediabanner.jpg" class"bg"/><div class"text&qu…

【数据结构】图——最短路径

最短路径问题&#xff1a;从在带权有向图G中的某一顶点出发&#xff0c;找出一条通往另一顶点的最短路径&#xff0c;最短也就是沿路径各边的权值总和达到最小。 最短路径分为图中单源路径和多源路径。 本文会介绍Dijkstra和Bellman-Ford解决单源路径的问题 Floyd-Warshall解…

iMazing2024Windows和Mac的iOS设备管理软件(可以替代iTunes进行数据备份和管理)

iMazing2024是一款兼容 Windows 和 Mac 的 iOS 设备管理软件&#xff0c;可以替代 iTunes 进行数据备份和管理。以下是一些 iMazing 的主要功能和优点&#xff1a; 数据备份和恢复&#xff1a;iMazing 提供了强大的数据备份和恢复功能&#xff0c;可以备份 iOS 设备上的各种数据…

基于EasyCVR视频汇聚系统的公安网视频联网共享视频云平台建设思路分析(一)

随着社会的发展和科技的进步&#xff0c;视频监控系统在各个领域的应用越来越广泛&#xff0c;视频云平台建设已经成为了行业数字化转型的重要一环。公安网视频汇聚联网共享云的建设需要充分考虑技术、架构、安全、存储、计算等多方面因素&#xff0c;以确保平台的稳定性和可用…