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

黑马程序员C++核心编程笔记--4 类和对象--多态

1.多态的基本概念

多态是C++面向对象三大特性之一

多态分为两类

  • 静态多态: 函数重载和运算符重载属于静态多态,复用函数名
  • 动态多态: 派生类和虚函数实现运行时多态

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

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

下面通过案例进行讲解多态

#include <iostream>
using namespace std;class Animal
{
public:// Speak函数就是虚函数// 在函数前加上 virtual,表示这是一个“虚函数”,编译器不会马上决定调用哪个版本的函数,// 而是等到程序运行时,根据对象真实的类型来决定调用哪个类的函数(运行时多态)。virtual void Speak(){cout << "动物在说话" << endl;}
};class Cat: public Animal
{
public:void Speak(){cout << "小猫在说话" << endl;}
};class Dog:public Animal
{
public:void Speak(){cout << "小狗在说话" << endl;}
};// 我们希望传入什么对象就调用什么对象的函数
// 如果函数地址在编译阶段就能确定,那么静态联编
// 如果函数地址在运行阶段才能确定,那么动态联编
void DoSpeak(Animal& animal)
{animal.Speak();
}// 多态满足条件:
// 1.有继承关系
// 2.子类重写父类中的虚函数
// 多态使用:
// 父类指针或引用指向子类对象void test()
{Cat cat;DoSpeak(cat);Dog dog;DoSpeak(dog);
}int main()
{test();return 0;
}

总结:

多态满足条件

  • 有继承关系

  • 子类重写父类中的虚函数

  • 多态使用条件

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

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

2.多态案例一:计算器类

示例:

#include <iostream>
using namespace std;// 普通实现
class Calculator
{
public:int m_Num1;int m_Num2;int getResult(string oper){if (oper == "+"){return m_Num1 + m_Num2;}else if (oper == "-"){return m_Num1 - m_Num2;}else if (oper == "*"){return m_Num1 * m_Num2;}// 如果要提供新的运算,需要修改源码}};// 普通实现测试
void test1()
{Calculator c;c.m_Num1 = 10;c.m_Num2 = 20;cout << "c.m_Num1 + c.m_Num2 = " << c.getResult("+") << endl;cout << "c.m_Num1 - c.m_Num2 = " << c.getResult("-") << endl;cout << "c.m_Num1 * c.m_Num2 = " << c.getResult("*") << endl;
}//多态实现
// 抽象计算器
// 多态优点:代码组织结构清晰,可读性强,利于前期和后期扩展以及维护
class AbstractCalculator
{
public:int m_Num1;int m_Num2;virtual int getResult(){return 0;}
};// 加法计算器
class AddCalculator :public AbstractCalculator
{
public:int getResult(){return m_Num1 + m_Num2;}
};// 减法计算器
class SubCalculator :public AbstractCalculator
{
public:int  getResult(){return m_Num1 - m_Num2;}
};// 乘法运算器
class MulCalculator :public AbstractCalculator
{
public:int getResult(){return m_Num1 * m_Num2;}
};void test2()
{// 创建加法计算器AbstractCalculator *abc = new AddCalculator;abc -> m_Num1 = 10;abc -> m_Num2 = 10;cout << "abc->m_Num1 + abc->m_Num2 = " << abc->getResult() << endl;delete abc;//创建减法计算器abc = new SubCalculator;abc->m_Num1 = 10;abc->m_Num2 = 10;cout << "abc->m_Num1 - abc->m_Num2 = " << abc->getResult() << endl;delete abc;//创建乘法计算器abc = new MulCalculator;abc->m_Num1 = 10;abc->m_Num2 = 10;cout << "abc->m_Num1 * abc->m_Num2 = " << abc->getResult() << endl;delete abc;
}int main() {//test01();test2();return 0;
}

总结:C++开发提倡利用多态设计程序架构,因为多态优点很多

3.虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容,因此可以将虚函数改为纯虚函数

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

当类中有了纯虚函数,这个类也称为抽象类

抽象类特点:

  • 无法实例化对象
  • 子类必须重写抽象类中的虚函数,否则也属于抽象类

示例:

#include <iostream>
using namespace std;class Base
{
public:// 纯虚函数// 类中只要有一个纯虚函数就称为抽象类// 抽象类无法实体化对象// 子类必须重写父类中的纯虚函数,否则也属于抽象类virtual void show() = 0;
};class Son : public Base
{
public:virtual void show(){cout << "show调用" << endl;}
};void test1()
{Base* base = NULL;// base = *new Base;    // 错误,抽象类无法实例化对象base = new Son;base->show();delete base;    // 使用完后要销毁
}int main()
{test1();return 0;
}

4.多态案例二:制作饮品

制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料

利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶

示例:

#include <iostream>
using namespace std;/*
* 制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料
* 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*/// 抽象制作饮品
class AbstractDrinkind
{
public:// 烧水virtual void Boil() = 0;// 冲泡virtual void Brew() = 0;// 倒入杯中virtual void PourInCup() = 0;// 加入辅料virtual void AddCondiments() = 0;// 规定流程void MakeDrink(){Boil();Brew();PourInCup();AddCondiments();}
};// 制作咖啡
class Coffee: public AbstractDrinkind
{
public://  烧水void Boil(){cout << "把水煮沸" << endl;}// 冲泡咖啡void Brew(){cout  << "用沸水冲泡咖啡" << endl;}// 倒入杯中void PourInCup(){cout  << "把咖啡倒进杯子" << endl;}// 加入辅料void AddCondiments(){cout  << "加糖和牛奶" << endl;}
};// 制作茶水
class Tea : public AbstractDrinkind
{
public://  烧水void Boil(){cout << "把水煮沸" << endl;}// 冲泡茶void Brew(){cout  << "用沸水浸泡茶叶" << endl;}// 倒入杯中void PourInCup(){cout << "把茶倒进杯子" << endl;}// 加入辅料void AddCondiments(){cout  << "加枸杞" << endl;}
};// 业务函数
void Dowork(AbstractDrinkind* drink)
{drink -> MakeDrink();delete drink;
}void test()
{Dowork(new Coffee);cout << "-----------------"  << endl;Dowork(new Tea);
}int main()
{test();return 0;
}

5.虚析构和纯虚析构

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

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

虚析构和纯虚析构共性:

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

虚析构和纯虚析构区别:

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

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

纯虚析构语法:

virtual ~类名() = 0;

类名::~类名(){}

#include <iostream>
using namespace std;class Animal
{
public:Animal(){cout << "Animal()" << endl;}virtual void Speak() = 0;// 析构函数加上virtual关键字,变成虚析构函数// virtual ~Animal()// {//     cout << "~Animal()" << endl;// }virtual ~Animal() = 0;
};Animal::~Animal()
{cout << "~Animal()" << endl;
}// 和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化class Cat:public Animal
{
public:string * m_name;Cat(string name){cout << "Cat构造函数调用" << endl;m_name = new string(name);}virtual void Speak(){cout <<  "m_name: " << *m_name << ": 喵喵喵" << endl;}~ Cat(){cout << "~Cat()" << endl;if (this -> m_name != nullptr){delete m_name;m_name = nullptr;}}
};void test01()
{Animal * animal = new Cat("Tom");animal ->  Speak();// 通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄露// 解决方法:给基类加一个虚析构函数// 虚析构函数用来解决通过父类指针释放子类对象delete animal;
}int main()
{test01();return 0;
}

6.多态案例三:电脑组装

案例描述
电脑主要组成部件为 CPU(用于计算),显卡(用于显示),内存条(用于存储)

将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例如Intel厂商和Lenovo厂商

创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口

测试时组装三台不同的电脑进行工作

示例

#include <iostream>
using namespace std;// 抽象cpu类
class CPU
{
public:// 抽象计算函数virtual void calculate() = 0;
};// 抽象显卡类
class GPU
{
public:// 抽象显示函数virtual void display() = 0;
};// 抽象内存条类
class Memory
{
public:// 抽象的存储函数virtual void storage() = 0;
};// 电脑类
class Computer
{
public:Computer(CPU* cpu, GPU* gpu, Memory* memory){m_cpu = cpu;m_gpu = gpu;m_memory = memory;}// 提供工作的函数void work(){// 让零件工作起来,调用接口m_cpu->calculate();m_gpu->display();m_memory->storage();}// 提供析构函数,释放3个电脑零件~Computer(){// 释放CPU零件if (m_cpu != nullptr){delete m_cpu;m_cpu = nullptr;}// 释放GPU零件if (m_gpu != nullptr){delete m_gpu;m_gpu = nullptr;}// 释放内存零件if (m_memory != nullptr){delete m_memory;m_memory = nullptr;}}
private:CPU* m_cpu;     // CPU的零件指针GPU* m_gpu;      // 显卡的零件指针Memory* m_memory;      // 内存条的零件指针
};// 具体厂商
//Intel厂商
class IntelCPU: public CPU
{
public:virtual void calculate(){cout << "Intel CPU calculate" << endl;}
};class IntelGpu: public GPU
{
public:virtual void display(){cout << "Intel GPU display" << endl;}
};class IntelMemory: public Memory
{
public:virtual void storage(){cout << "Intel Memory storage" << endl;}
};// lenovo厂商
class LenovoCPU: public CPU
{
public:virtual void calculate(){cout << "Lenovo CPU calculate" << endl;}
};class LenovoGPU: public GPU
{
public:virtual void display(){cout << "Lenovo GPU display" << endl;}
};class LenovoMemory: public Memory
{
public:virtual void storage(){cout << "Lenovo Memory storage" << endl;}
};void test()
{// 第一台电脑零件CPU *intelCpu = new LenovoCPU();GPU *intelGpu = new LenovoGPU();Memory *intelMemory = new LenovoMemory();cout << "第一台电脑开始工作:" << endl;Computer *computer1 = new Computer(intelCpu, intelGpu, intelMemory);computer1->work();delete computer1;cout << "----------------------"  << endl;cout << "第二台电脑开始工作:" << endl;// 第二台电脑组装Computer * computer2 = new Computer(new LenovoCPU, new LenovoGPU, new LenovoMemory);computer2->work();delete computer2;cout  << "----------------------"  << endl;cout << "第三台电脑开始工作:" << endl;// 第三台电脑组装Computer * computer3 = new Computer(new LenovoCPU, new IntelGpu, new LenovoMemory);computer3 ->work();delete computer3;}int main() {test();return 0;
}

相关文章:

  • 1.文件操作相关的库
  • Java Netty 中处理粘包和半包问题的解决方案 | TCP消息完整性校验(XOR )
  • 基于GPT-SoVITS-v4-TTS的音频文本推理,流式生成
  • SOC-ESP32S3部分:25-HTTP请求
  • 移动AI神器GPT Mobile:多模型自由切换
  • 基于SpringBoot运动会管理系统设计和实现(源码+文档+部署讲解)
  • 抛砖引玉:RadarDet4D,NuScenes数据集Radar模态目标检测第二名(即将开源)
  • 道路目标检测和分类数据集
  • 神经网络中的梯度消失与梯度爆炸
  • TC3xx学习笔记-启动过程详解(一)
  • 【MySQL基础】库的操作:创建、删除与管理数据库
  • Docker私有仓库Harbor安装指南
  • 《深度剖析:基于Meta的GameFormer构建自博弈AI游戏代理》
  • 第12次09:展示收货地址和新增地址
  • 信号处理基础到进阶再到前沿
  • Windows不关防火墙,安全开放端口方法
  • Leetcode 2123. 使矩阵中的 1 互不相邻的最小操作数
  • ChatOn:智能AI聊天助手,开启高效互动新时代
  • 摩尔投票算法原理实现一文剖析
  • NodeJS全栈WEB3面试题——P3Web3.js / Ethers.js 使用
  • 设计网站排名/无锡网站制作优化
  • 珠海手机微信网站建设小程序开发/网推团队
  • 山东青岛网站建设公司/4414站长平台
  • 在国外建网站方便吗/seo的工作内容主要包括
  • wordpress隐藏网站/百度一下知道官网
  • 餐饮 网站建设/黄山seo