什么是多态性?C++中如何实现多态?多态性的好处是什么?

1) 什么是多态性?C++中如何实现多态?

函数重写(覆盖):

定义:子类重新定义父类中有相同名称,返回值和参数的虚函数,主要在继承关系中出现。

父类中的fun函数是虚函数,子类中有返回值,名字 参数 相同的fun函数,那么子类中的fun函数(无论加不加virtual)都是虚函数

基本条件:

  • 重写的函数和被重写的函数必须都虚(virtual)函数,并分别位于基类和派生类中
  • 重写的函数和被重写的函数,返回值,函数名和函数参数必须完全一致;

函数隐藏:子类中只要和父类函数名字相同不是重写,一定是函数隐藏

多态的基本概念:
  • 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
  • 动态多态: 派生类和虚函数实现运行时多态(父类的指针或引用指向子类对象,并且调用子类的重写函数)

静态多态和动态多态区别:

  • 静态多态的函数地址早绑定 - 编译阶段确定函数地址
  • 动态多态的函数地址晚绑定 - 运行阶段确定函数地址

父类指针或引用指向子类对象时,函数隐藏不会调用子类中的函数而是调用父类中的函数

调用的函数是隐藏函数时,调用函数的指针或对象是什么类型调用哪里的函数

总结:

多态满足条件

  • 有继承关系
  • 子类重写父类中的虚函数

多态使用条件

  • 父类指针或引用指向子类对象

重写:函数返回值类型 函数名 参数列表 完全一致称为重写

多态的实现:

为了实现 C++ 的多态,C++ 使用了一种动态绑定的技术。这个技术的核心是虚函数表。下面介绍虚函数表是如何实现动态绑定的。

类的虚函数表:
  • 每个包含了虚函数的类都包含一个虚表(存放虚函数指针的数组)。
  • 当一个类(B)继承另一个类(A)时,类 B 会继承类 A 的函数的调用权。所以如果一个基类包含了虚函数,那么其继承类也可调用这些虚函数,换句话说,一个类继承了包含虚函数的基类,那么这个类也拥有自己的虚表。
  • 以下的代码。类 A 包含虚函数vfunc1,vfunc2,由于类 A 包含虚函数,故类 A 拥有一个虚表。
class A {
public:
    virtual void vfunc1();
    virtual void vfunc2();
    void func1();
    void func2();
private:
    int m_data1, m_data2;
};
class B : public A{//此时类B也拥有自己的虚表
};
纯虚函数和抽象类:

纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;

当类拥有纯虚函数,这个类也称为抽象类(一般作为基类)

抽象类特点:

  • 无法实例化对象(抽象类不能创建对象)
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
  • 纯虚函数在虚表中存放的是 0

虚函数在虚表中存放的是函数地址

虚析构和纯虚析构:

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码(如果不加virtual将父类的析构改为虚析构或者纯虚析构 子类的析构会将父类的析构隐藏 从而造成内存泄露)

解决方式:将父类中的析构函数改为虚析构或者纯虚析构

父类指针指向子类对象,只能调用父类成员函数

虚析构和纯虚析构共性:

  • 可以解决父类指针释放子类对象
  • 都需要有具体的函数实现

虚析构和纯虚析构区别:

  • 如果是纯虚析构,该类属于抽象类,无法实例化对象

虚析构语法: virtual ~类名(){}

纯虚析构语法: virtual ~类名() = 0;

示例:

#include<iostream>
#include<string>
#include<vector>
using namespace std;
 
class Animal
{
public:
    Animal()
    {
        cout << "animal构造" << endl;
    }
  
  //如果不加virtual 子类的析构会将父类的析构隐藏 从而造成内存泄露
    virtual ~Animal()
    {
        cout << "animal析构" << endl;
    }
};
 
class cat :public Animal
{
public:
    cat()
    {
        cout << "cat构造" << endl;
    }
    ~cat()
    {
        cout << "cat析构" << endl;
    }
};
 int main() {
    Animal *a = new cat;//父类指针指向子类对象
    delete a;
    return 0;
}

2)多态性的好处是什么? 

多态性在面向对象编程中有以下几个主要好处:

一、提高代码的可扩展性和可维护性

1. 可扩展性

当需要添加新的功能或类型时,可以在不修改现有代码的基础上进行扩展。例如,在一个图形绘制系统中,如果要添加一种新的图形类型,只需要从基类派生一个新的类并实现相应的虚函数,而不需要修改已有的绘制代码。

这样可以避免对现有系统的大规模修改,降低引入新错误的风险。

2. 可维护性

由于多态性使得代码的结构更加清晰,不同类型的对象的行为被封装在各自的类中,通过统一的接口进行调用。这使得代码更容易理解和维护。

当需要修改某个特定类型的行为时,只需要在该类型的类中进行修改,而不会影响其他类型的对象。

二、增强代码的灵活性和通用性

1. 灵活性

多态性允许根据不同的情况动态地选择不同的实现。例如,在一个游戏中,不同的角色可能有不同的攻击方式,可以通过多态性在运行时根据角色的类型选择合适的攻击函数。

这种灵活性使得代码能够适应不同的场景和需求变化。

2. 通用性

可以编写通用的代码来处理不同类型的对象。例如,可以定义一个函数,接受一个基类类型的参数,然后通过多态性调用不同派生类的虚函数,实现对不同类型对象的统一处理。

这样的通用代码可以提高代码的复用性,减少重复编写类似代码的工作量。

三、实现代码的封装和信息隐藏

1. 封装

多态性可以将不同类型的实现细节封装在各自的类中,只通过基类的接口暴露必要的功能。这样可以避免外部代码直接依赖于具体的实现细节,提高代码的稳定性。

例如,在一个图形绘制系统中,外部代码只需要知道如何调用绘制函数,而不需要了解不同图形的具体绘制算法。

2. 信息隐藏

通过多态性,可以隐藏不同类型对象的内部状态和实现细节,只暴露必要的接口。这有助于提高代码的安全性,防止外部代码意外地修改内部状态。

同时,信息隐藏也使得代码更加易于理解和维护,因为外部代码不需要关心复杂的内部实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值