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

C++进阶----多态

目录

  • 引言
    • 1.多态的概念
    • 2.多态的定义及实现
      • 2.1 多态的构成条件
      • 2.2虚函数
      • 2.3 虚函数的重写
      • 2.4 关键字override和final
      • 2.5 重载、覆盖(重写)、隐藏对比
    • 3.抽象类
      • 3.1 抽象类概念
    • 4.多态的原理
      • 4.1 虚函数表
      • 4.2虚函数表的底层
      • 4.3多态的原理
      • 4.4 动态绑定和静态绑定
    • 5.单继承和多继承关系中的虚函数表
      • 5.1 单继承中的虚函数表
      • 5.2 多继承中的虚函数表
    • 6.总结

引言

C++的三大的特性:封装、继承、多态
多态是一种面向对象编程的特性,它允许不同类的对象对同一消息做出响应。
在C++中,多态主要通过虚函数和抽象类来实现。虚函数允许派生类重写基类的方法,而抽象类则可以定义一个接口,强制派生类实现特定的方法。这样,基类指针或引用可以指向派生类对象,从而在运行时实现多态行为。

1.多态的概念

1.1概念

多态(Polymorphism)是面向对象编程(OOP)的一个基本概念,它允许同一个接口接受不同的数据类型。(简单来说就是去完成某个行为,当不同的对象去完成时会产生出不同的状态,比如火车票,成人买成人全价票,儿童买半票,学生买票享有学生的专属折扣票军人买票可以优先买票)

2.多态的定义及实现

2.1 多态的构成条件

多态是在不同继承关系的类对象,在这个前提下构成多态的俩个条件:

  1. 必须通过基类指针或者引用调用虚函数
  2. 被调用的函数必须是虚函数

在这里插入图片描述

2.2虚函数

虚函数:被virtual修饰的类成员函数称为虚函数,无法通过自己本身来实例化

class Person{
public:virtual void BuyTicket(){cout<<"买票-全价"<<endl;}
};

2.3 虚函数的重写

虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数.

#include<iostream>
using namespace std;
class father
{
public:virtual void Buysth(){ cout << "dad will take you shoping" << endl; }
};class son:public father
{
public:virtual void Buysth(){ cout << "I will go shoping by meself" << endl; }
};void fun(father& f)
{f.Buysth();
}int main()
{father f;son s;f.Buysth();s.Buysth();fun(f);fun(s);//s的切片return 0;
}

在这里插入图片描述

虚函数重写的俩个例

  1. 协变(基类与派生类虚函数返回值类型不同)

基类虚函数返回基类对象的指
针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变

  1. 析构函数的重写

如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,
都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,
看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处
理,编译后析构函数的名称统一处理成destructor

2.4 关键字override和final

  1. find

关键字override用于显式指定派生类函数覆盖了基类的虚函数;final关键字则用于阻止一个虚函数在其派生类中被覆盖,或者阻止一个类被继承。

class D{
public:
virtual void d() final{}//基类
}
  1. override

override关键字主要用于检查派生类的函数是否真正的重写了基类的虚函数,如果没有则会报错。调用覆盖的函数时,会调用派生类的版本,而不是基类的版本。

class D{
publicvirtual void d ()voerride{}//派生类
}

2.5 重载、覆盖(重写)、隐藏对比

在这里插入图片描述

3.抽象类

3.1 抽象类概念

在虚函数的后面写上 =0 ,则这个函数为纯虚函数。

抽象类是一个特殊的类,它是为了表示一种抽象的概念而设立的,不能被实例化。抽象类通常作为一种基本形态,由它派生出各种具体类。抽象类至少包含一个纯虚函数。

class father
{
public:virtual void Buysth() =0 { cout << "dad will take you shoping" << endl; } 
};class son:public father
{
public:virtual void Buysth(){ cout << "I will go shoping by meself" << endl; }
};

4.多态的原理

4.1 虚函数表

虚函数表是C++中的一个概念,用于支持多态性。每个具有虚函数的对象都有一个指向虚函数表的指针,虚函数表中包含了对象的虚函数的地址。

class father
{
public:virtual void Buysth() { cout << "dad will take you shoping" << endl; }
private:int _x;
};
class A
{
public:void a(){}
private:int _x;
};
int main()
{father f;A a;return 0;
}

在这里插入图片描述

可以看出存在虚函数的类中,大小和普通类的大小是不一样的。

除了_x成员,还多一个__vfptr放在对象的前面(注意有些平台可能会放到对象的最后面,这个跟平台有关),对象中的这个指针我们叫做虚函数表指针(v代表virtual,f代表function

4.2虚函数表的底层

class Base
{
public:virtual void fun1() { cout << "fun1()" << endl; }virtual void fun2() { cout << "fun2()" << endl; }
private:int _B = 0;
};
class A:public Base
{
public:void fun1() { cout << "A::fun1()" << endl; }
private:int _a = 1;
};class B :public Base
{
public:void fun1() { cout << "B::fun1()" << endl; }void fun2() { cout << "B::fun2()" << endl; }
private:int _b = 2;
};int main()
{Base base;A a;B b;return 0;
}

在这里插入图片描述

可以看出每个实例类的虚函数表的地址和所包括的虚函数都不一样,构成重写的会生成新的虚函数,而没有构成重写的会继承基类的虚函数

4.3多态的原理

多态的实现原理基于两个关键概念:虚函数表和虚函数表指针。每个多态类都有一张虚函数表,这张表中存储了该类的虚函数地址。每个多态类的对象都有一个虚函数表指针,该指针指向该类的虚函数表。当我们通过基类的指针调用虚函数时,程序会根据这个指针指向的虚函数表中的地址去调用对应的函数,从而实现了多态。

通过调用基类的引用和指针,派生类的指针和引用,来区别不继承类和基类的虚函数调用。满足多态以后的函数调用,不是在编译时确定的,是运行起来以后到对象的中取找的。不满足多态的函数调用时编译时确认好的

4.4 动态绑定和静态绑定

  1. 静态绑定又称为前期绑定(早绑定),在程序编译期间确定了程序的行为也称为静态多态

比如:函数重载

  1. 动态绑定又称后期绑定(晚绑定),是在程序运行期间,根据具体拿到的类型确定程序的具体行为,调用具体的函数,也称为动态多态

5.单继承和多继承关系中的虚函数表

5.1 单继承中的虚函数表

在4.2中的虚函数表底层中就是常见的单继承

在这里插入图片描述

5.2 多继承中的虚函数表

class Base
{
public:virtual void fun1() { cout << "fun1()" << endl; }virtual void fun2() { cout << "fun2()" << endl; }
private:int _B = 0;
};class More
{
public:virtual void fun1(){}virtual void fun2(){}
private:int _M = 0;
};class A:public Base,public More
{
public:void fun1() { cout << "A::fun1()" << endl; }
private:int _a = 1;
};int main()
{Base base;A a;return 0;
}

在这里插入图片描述

可以看出,多继承虚函数的派生类也会有多应多个的虚函数表(虚函数指针表)

6.总结

在C++中,多态性是一种允许不同类型的对象对同一消息做出不同响应的特性。通过虚函数和继承,我们可以实现运行时多态。运行时多态是面向对象编程的三大特性之一,它极大地增强了程序的可扩展性。但是,我们也要注意虚函数会带来一些性能开销,因此在使用时需要权衡利弊。

相关文章:

  • Python笔记:VS2013编译Python-3.5.10
  • 【EDA】EDA中聚类(Clustering)和划分(Partitioning)的应用场景
  • 潮了 低配电脑6G显存生成60秒AI视频 本地部署/一键包/云算力部署/批量生成
  • 第3.2节 Android应用调用链路分析
  • 数字化技术的五个环节:大数据、云计算、人工智能、区块链、移动互联网
  • 深入理解指针(4)
  • 机器学习的基本概念
  • 面向智能家居安全的异常行为识别与应急联动关键技术研究与系统实现(源码+论文+部署讲解等)
  • 第二章 信息技术发展(2.1 信息技术及其发展)
  • 高频面试题:如何保证数据库和es数据一致性
  • 11.ArkUI Tabs的介绍和使用
  • 跟我学C++中级篇——处理对象的复制
  • 【科研绘图系列】R语言绘制区间点图(dot plot)
  • Vue前端学习笔记
  • 什么是测试驱动开发(TDD)?
  • Safety Estimands与Efficacy Estimands的差异剖析
  • UR5 UR5e机器人URDF文件
  • ai聊天流式响应,阻塞式和流式响应 nginx遇到的坑
  • 科技与商业动态简报
  • 基于python代码的通过爬虫方式实现快手发布视频(2025年4月)
  • 远程控制、窃密、挖矿!我国境内捕获“银狐”木马病毒变种
  • 湖南省郴州市统战部部长黄峥嵘主动交代问题,接受审查调查
  • 中国专家组赴缅开展地震灾害评估工作
  • 吃饭睡觉打国米,如今的米兰把意大利杯当成宝
  • 温氏股份一季度归母净利润20.01亿元,同比扭亏为盈
  • 锚定“水库不垮坝”目标,水利部部署今年水库安全度汛工作