当前位置: 首页 > news >正文

[C++面向对象语言第三大特性] :多态

目录

  • 多态的概念
    • 多态的构成条件
    • 虚函数
    • 重写
  • 区别重写和重载
  • 构成多态后的效果
  • 有关于继承和多态的关键字
  • 特殊的类 :纯虚类(抽象类)

多态的概念

多态按字面的意思就是多种形态。
继承多态的基础
当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。

C++ 多态允许使用基类指针或引用来调用子类的重写方法,从而使得同一接口可以表现不同的行为。
多态使得代码更加灵活和通用,程序可以通过基类指针或引用来操作不同类型的对象,而不需要显式区分对象类型。这样可以使代码更具扩展性,在增加新的形状类时不需要修改主程序。

多态的构成条件

1.必须由指针或者引用调用虚函数
2.基类和派生类的虚函数必须构成重写(所以继承是多态的条件)

虚函数

在基类中声明一个函数为虚函数,使用关键字virtual。
派生类可以重写(override)这个虚函数。
调用虚函数时,会根据对象的实际类型来决定调用哪个版本的函数。

重写

重写的概念非常简单,即派生类有一个,返回值类型,函数名,参数列表与基类完全相同的相同函数

注意点1 : 重写只是对函数体的重写(即只针对函数的实现不同)
在这里插入图片描述

注意点2 :特别的析构函数的重写
基类和派生类的析构函数一定是不同名的啊,怎么构成重写?答:编译器会统一把析构函数名处理成 deseructor,就是为了让他构成多态

这里p2是开了student空间的大小,但是却是person类型,这里又不构成多态
所以P2调基类的析构函数导致student有些部分没有被析构到,所以内存泄漏
在这里插入图片描述

使用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() {Person* p1 = new Person;delete p1;  // 调用 Person 的虚析构函数Person* p2 = new Student;delete p2;  // 因析构函数是虚函数,会先调用 Student::~Student(),再调用 Person::~Person()return 0;
}

这就是C++核心指南中有这么一条原则

C.35: A base class destructor should be either public and virtual, or protected and non-virtual 

区别重写和重载

重载通常在同一作用域下,ex:一个类中,一个命名空间中,一个全局作用域中
而重写是不同作用域下的(最常见的就是基类和派生类中)

在这里插入图片描述

构成多态后的效果

1.构成多态:

#include <iostream>
using namespace std;// 基类 Person
class Person
{
public:virtual void BuyTicket(){cout << "买票全价" << endl;}
};// 派生类 Student(公有继承 Person)
class Student : public Person
{
public:// 重写(override)基类的虚函数 BuyTicketvirtual void BuyTicket(){cout << "买票半价" << endl;}
};// 接收 Person 引用的函数,会触发多态行为
void Func(Person& people)
{people.BuyTicket();
}// 测试函数
void Test()
{Person Mike;       // 定义 Person 类型对象 MikeFunc(Mike);        // 调用 Func,传入 Mike(调用 Person::BuyTicket)Student Johnson;   // 定义 Student 类型对象 JohnsonFunc(Johnson);     // 调用 Func,传入 Johnson(调用 Student::BuyTicket,多态)
}int main()
{Test();return 0;
}

完成了构成图多态的两个条件,Mike的引用和Johnson引用将调用不同的虚函数,构成了多态指针或引用的指向与创建时指向的类型有关

2.不构成多态

#include <iostream>
using namespace std;// 基类:动物
class Animal {
public:// 普通成员函数(非虚函数)void Speak() {cout << "动物发出声音" << endl;}// 普通析构函数(非虚函数)~Animal() {cout << "Animal析构函数被调用" << endl;}
};// 派生类:猫(继承自动物)
class Cat : public Animal {
public:// 与基类同名的普通成员函数(非虚函数,不构成重写)void Speak() {cout << "猫喵喵叫" << endl;}// 派生类普通析构函数(非虚函数)~Cat() {cout << "Cat析构函数被调用" << endl;}
};int main() {// 基类指针指向基类对象Animal* a1 = new Animal;a1->Speak();  // 调用基类的Speak(根据指针类型)delete a1;    // 调用基类的析构函数// 基类指针指向派生类对象(不构成多态)Animal* a2 = new Cat;a2->Speak();  // 仍然调用基类的Speak(因无虚函数,不根据对象实际类型)delete a2;    // 仅调用基类的析构函数(派生类析构未被调用,可能导致资源泄漏)return 0;
}

因为缺少虚函数的重写所以不构成多态,对象调用的类型与其创建时指向的类型无关,之和其本身的类型有关,在上述代码片中
本身的类型就是“Animal”

有关于继承和多态的关键字

final:表示最终
修饰虚函数,该虚函数无法被重写
修饰类,该类成为最终类,无法被继承

在这里插入图片描述
在这里插入图片描述

override : 修饰虚函数,该虚函数无法被重写
可以检测出一些很“恶心”的bug,比如下图防止check名字写错写成chcek了
在这里插入图片描述

特殊的类 :纯虚类(抽象类)

包含纯虚函数的类叫纯虚类(抽象类),纯虚类无法实例化生成对象
纯虚函数:在虚函数后面 加上 =0 就是纯虚函数了

纯虚类作为基类的作用:
纯虚类一定包含了纯虚函数,它规定了派生类必须重写这个纯虚函数否则派生类无法生成实例
因此纯虚类的作用就是规范,派生类必须对某个纯虚函数进行重写
另外纯虚函数也体现了接口继承

在这里插入图片描述
在这里插入图片描述
现在我们已经完成面向对象语言三大特性,封装,继承,多态基本的学习了,后续的博客会讲解,多态和虚继承的原理(即虚函数指针表和虚基表)

http://www.dtcms.com/a/504041.html

相关文章:

  • 网站建设流程要多少钱新开传奇网站999
  • 优化网站推广网站广东网站建设找哪家
  • 均值回归(配对交易)策略
  • 【每日英语(1019)】相关文章:政要新闻,健身,法案,漫画
  • 网站建设初步课程介绍济南国画网站济南网站建设公司
  • 【linux学习篇】多线程之间资源共享---共享内存方式
  • 除了有效市场假说,还有哪些理论能更好的解释经济或者金融活动
  • 咨询手机网站建设平台400电话网站源码
  • 【阿里巴巴大数据之路】事实表设计
  • 建设网站之前都需要准备什么问题广东vs北京首钢
  • 四川住房城乡建设厅网站企业模拟网站建设
  • 多媒体标签全解析:img、audio、video标签详解
  • 【139套财务会计excel模板】免费分享
  • 免费网站如何被百度收录wordpress图片特效
  • 网站框架有哪些网站页面优化怎么做
  • 虚幻引擎虚拟制片入门教程 之 Sequencer 常用技巧
  • 个人网站备案简介怎么写企业网站建设的征求意见
  • 如何做网络营销推广工作做外贸seo优化的上市公司
  • 怎样建网站买东西电商网站管理系统模板下载
  • ping一下新浪网站怎么做树莓派wordpress博客
  • 网站建设服务器租用找网站的方法
  • 解码Linux文件IO之LCD屏原理及应用
  • Java集合体系 —— Map篇
  • 大连网站制作代理价格北京小程序开发价格
  • 内蒙古建设安全监督网站东道 网站建设
  • 跳格子游戏(1)
  • 谈谈你对Mysql 锁的理解
  • 网站开发有哪些模块想做分销商有什么平台
  • P14245 [CCPC 2024 Shandong I] 左移题解
  • 网站做支付宝花呗分期有哪些做家教网站