28.C++多态1 (多态的概念与简单使用,虚函数,final,override)

devtools/2025/2/26 5:32:29/

⭐上篇文章:27.C++继承 3 (复杂的菱形继承与菱形虚拟继承)-CSDN博客

⭐本篇代码:c++学习/17.C++三大特性-多态 · 橘子真甜/c++-learning-of-yzc - 码云 - 开源中国 (gitee.com)

⭐标⭐是比较重要的部分

目录

一. C++多态简介

1.1 构成多态的两个必要条件 

二. virtual关键字与虚函数

 1.1 使用虚函数测试多态

1.2 virtual关键字的用法

三. 虚函数重写的两个例外 

3.1 协变

3.2 析构函数 ⭐

四. final 和 override关键字 

        4.1 final 

4.2 override 


一. C++多态简介

        多态是指不同有继承关系的对象在调用同一个函数之后,会有不同的结果。比如学生票和成人票。

        Student继承了Person,但是Studenet买票是半价,而Person是全价

1.1 构成多态的两个必要条件 

1 必须通过基类的指针或者引用去调用虚函数

2 被调用的函数必须是虚函数,且派生类必须完成对虚函数重写

二. virtual关键字与虚函数

        用virtual修饰的成员函数就是虚函数

比如:下面代码中的buyTickets就是虚函数

#include <iostream>
using namespace std;class Person
{
public:virtual void buyTickets(){cout << "全价买票" << endl;}
};int main()
{}

 1.1 使用虚函数测试多态

        

#include <iostream>
using namespace std;class Person
{
public:virtual void buyTickets(){cout << "全价买票" << endl;}
};class Student : public Person
{
public:virtual void buyTickets(){cout << "半价买票" << endl;}
};void test(Person& tmp)
{tmp.buyTickets();
}int main()
{Person p1;Student s1;Person* tmp1 = &p1;Student* tmp2 = &s1;//测试指针cout << "使用指针完成多态" << endl;tmp1->buyTickets();tmp2->buyTickets();//测试引用cout << "使用引用完成多态" << endl;test(p1);test(s1);return 0;
}

测试结果如下:

        可以看到,我们使用基类的指针或者引用成功的调用了基类和派生类的函数,从而达到一种多态的效果 

1 如果两个有继承关系的成员函数满足多态的条件,指针指向哪个对象或者引用哪个对象就调用这个对象的成员函数

2 如果不满足多态条件,调用的类型对象是谁,就调用该对象的成员函数

3 重写虚函数需要保持返回值类型,名称,参数列表都一致

1.2 virtual关键字的用法

1 virtual修饰类的继承中,完成虚继承,解决菱形继承中的冗余性和二义性

2 virtual修饰成员函数,变为虚函数完成函数的重写

三. 虚函数重写的两个例外 

3.1 协变

        如果派生类重写虚函数的时候,两个函数的返回值类型不同,但是都为本身类的指针或者引用的时候。也构成虚函数重写

如下面的代码,基类返回基类的指针,派生类返回派生类的指针 

#include <iostream>
using namespace std;class Person
{
public:virtual Person* buyTickets(){cout << "全价买票" << endl;return this;}
};class Student : public Person
{
public:virtual Student* buyTickets(){cout << "半价买票" << endl;return this;}
};void test(Person& tmp)
{tmp.buyTickets();
}int main()
{Person p1;Student s1;Person* tmp1 = &p1;Student* tmp2 = &s1;//测试指针cout << "使用指针完成多态" << endl;tmp1->buyTickets();tmp2->buyTickets();//测试引用cout << "使用引用完成多态" << endl;test(p1);test(s1);return 0;
}

3.2 析构函数 ⭐

        如果有继承关系,并且我们需要使用多态的时候。需要使用virtual修饰析构函数,将其定义为虚函数。        

        否则当我们使用基类的指针或者引用之后,销毁这个变量的时候就会由于隐藏只调用当前对象的析构函数。

比如:

#include <iostream>
using namespace std;class A
{
public:virtual void test(){}~A() { cout << " ~A()" << endl; }
};
class B :public A
{
public:virtual void test() {}~B() { cout << " ~B()" << endl; }
};int main()
{//使用多态A* a = new A();A* b = new B();a->test();b->test();//删除变量delete a;delete b;return 0;
}

        在上面的代码中,我们使用多态去调用test。然后使用delete删除变量。正常来说,析构函数的调用顺序是 ~A ()        ~B()         ~A()

测试结果如下:

        可以看到,只调用了A的析构函数。这是因为我们没有对析构函数进行虚函数重写,导致B类的析构函数和A类的析构函数构成隐藏,又由于我们的指针定义的时候是A,所以不会调用B的析构函数,从而导致内存泄漏

对析构函数进行重写

#include <iostream>
using namespace std;class A
{
public:virtual void test(){}virtual ~A() { cout << " ~A()" << endl; }
};
class B :public A
{
public:virtual void test() {}virtual ~B() { cout << " ~B()" << endl; }
};int main()
{//使用多态A* a = new A();A* b = new B();a->test();b->test();//删除变量delete a;delete b;return 0;
}

可以看到,成功的调用了B的析构函数。解决了内存泄漏问题

四. final 和 override关键字 

        4.1 final 

final有两个用法

final修饰类,这个类不能被继承。

final修饰成员函数,这个成员函数不能被重写

修饰虚函数 

 修饰类

 

4.2 override 

        override修饰成员函数,会检查这个成员函数是否重写了父类的函数,如果不构成重写,就会显示报错

举例:

#include <iostream>
using namespace std;class A 
{
public:virtual void test(){}void f(){}
};class B :public A
{
public:virtual void  test() override {}virtual void f()override
};int main()
{return 0;
}

无法通过编译 


http://www.ppmy.cn/devtools/162735.html

相关文章

装箱和拆箱是什么?(C#)

在 C# 中&#xff0c;装箱&#xff08;Boxing&#xff09;和拆箱&#xff08;Unboxing&#xff09;是值类型&#xff08;Value Type&#xff09;和引用类型&#xff08;Reference Type&#xff09;之间相互转换的过程。 目录 1 装箱 2 拆箱 3 性能影响 1 装箱 装箱是将值…

axios几种请求类型的格式

Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;广泛用于浏览器和 Node.js 中发送 HTTP 请求。它支持多种请求格式&#xff0c;包括 GET、POST、PUT、DELETE 等。也叫RESTful 目录 一、axios几种请求类型的格式 1、get请求 2、post请求 3、put请求 4、delete请求 二…

Visual Studio Code 跨平台安装与配置指南(附官方下载链接)

一、软件定位与核心功能 Visual Studio Code&#xff08;简称VS Code&#xff09;是微软开发的开源跨平台代码编辑器&#xff0c;支持超过50种编程语言的智能补全、调试和版本控制功能。2025版本新增AI辅助编程模块&#xff0c;可自动生成单元测试代码和API文档注释。 二、下载…

选择排序:简单高效的选择

大家好&#xff0c;今天我们来聊聊选择排序&#xff08;Selection Sort&#xff09;算法。这是一个非常简单的排序算法&#xff0c;适合用来学习排序的基本思路和操作。选择排序在许多排序算法中以其直观和易于实现的特点著称&#xff0c;虽然它的效率不如其他高效算法&#xf…

VS2022配置FFMPEG库基础教程

1 简介 1.1 起源与发展历程 FFmpeg诞生于2000年&#xff0c;由法国工程师Fabrice Bellard主导开发&#xff0c;其名称源自"Fast Forward MPEG"&#xff0c;初期定位为多媒体编解码工具。2004年后由Michael Niedermayer接任维护&#xff0c;逐步发展成为包含音视频采…

服务器释放screen资源(Detached状态并不会释放资源)

你可以使用 screen 命令来列出所有会话并手动关闭它们&#xff0c;或者直接终止所有的会话来释放资源。以下是如何操作的步骤&#xff1a; 1. 列出所有 screen 会话 你已经使用 screen -ls 列出了当前所有的 screen 会话。输出中显示了每个会话的 ID 和状态&#xff08;Detac…

并发 -- 无锁算法与结构

文章目录 什么是无锁算法什么是原子变量什么是CAS操作Compare-And-Swap Weak在哪些情况下会失败举例说明无锁结构无锁结构的问题 什么是无锁算法 无锁算法&#xff08;Lock-Free Algorithm&#xff09;是一种并发编程技术&#xff0c;旨在实现多线程环境下的高效数据共享&…

Windows10配置C++版本的Kafka,并进行发布和订阅测试

配置的环境为&#xff1a;Release x64下的环境 完整项目&#xff1a;https://gitee.com/jiajingong/kafka-publisher 1、首先下载相应的库文件&#xff08;.lib&#xff0c;.dll&#xff09; 参考链接&#xff1a; GitHub - eStreamSoftware/delphi-kafka GitHub - cloade…