[C++核心编程](九):类和对象——多态**

目录

多态的分类

多态的原理剖析

多态的优点

纯虚函数和抽象类

虚析构和纯虚析构


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

多态的分类

  • 静态多态

        -函数重载运算符重载属于静态多态,复用函数名

        -函数地址绑定-编译阶段确定函数地址

  • 动态多态

        -派生类虚函数实现运行时多态

        -函数地址绑定-运行阶段确定函数地址

动态多态满足条件:

        1.继承关系

        2.子类要重写(函数返回值类型、函数名、参数列表完全相同)父类的虚函数

动态多态的使用:

        父类的指针或者引用 指向 子类的对象

#include <iostream>
#include <string>using namespace std;class Animal
{
public://虚函数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();
}void test(void)
{Cat cat;dospeak(cat);Dog dog;dospeak(dog);
}int main(void)
{test();return 0;
}

多态的原理剖析

        父类内部结构vfptr-虚函数(表)指针 指向 vftable(表内记录虚函数的地址)

        当子类重写父类的虚函数:子类中的虚函数表内部会替换成子类的虚函数地址

        当父类的指针或者引用指向子类对象时,发生多态。

多态的优点

  • 代码组织结构清晰
  • 可读性强
  • 利于前期和后期的扩展和维护
  • (开闭原则)
#include <iostream>
#include <string>using namespace std;
//举例实现一个简易的计算器
class AbstractCalulator
{
public://虚函数virtual int getResult(){return 0;}int n_number;int m_number;
};class AddCalculator :public AbstractCalulator
{
public:int getResult(){return n_number + m_number;}
};class SubCalculator :public AbstractCalulator
{
public:int getResult(){return n_number - m_number;}
};class MulCalculator :public AbstractCalulator
{
public:int getResult(){return n_number * m_number;}
};void test(void)
{AbstractCalulator* abc = new AddCalculator;abc->n_number = 10;abc->m_number = 10;cout << abc->n_number << "+" << abc->m_number << "=" << abc->getResult() << endl;delete abc;abc = new SubCalculator;abc->n_number = 10;abc->m_number = 10;cout << abc->n_number << "-" << abc->m_number << "=" << abc->getResult() << endl;delete abc;abc = new MulCalculator;abc->n_number = 10;abc->m_number = 10;cout << abc->n_number << "*" << abc->m_number << "=" << abc->getResult() << endl;delete abc;
}int main(void)
{test();return 0;
}

 纯虚函数和抽象类

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

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

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

   抽象类特点:

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
#include <iostream>
#include <string>using namespace std;class Base
{
public:virtual void func() = 0;};class Son:public Base
{
public:void func(){cout << "Son 's func()" << endl;}
};void test(void)
{//Base base; 抽象类无法实例化对象//new Base;  抽象类无法实例化对象Base * base = new Son;base->func();
}int main(void)
{test();return 0;
}

虚析构和纯虚析构

如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码导致内存泄漏,解决办法是将父类的析构函数改为虚析构或者纯虚析构;

虚析构和纯虚析构的共性

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

虚析构和纯虚析构的区别

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

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

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

#include <iostream>
#include <string>using namespace std;class AbstractAnimal
{
public:AbstractAnimal(){cout << "AbstractAnimal 构造函数调用" << endl;}//virtual ~AbstractAnimal()//{//	cout << "AbstractAnimal 析构函数调用" << endl;//}virtual ~AbstractAnimal() = 0;virtual void speak() = 0;
};AbstractAnimal::~AbstractAnimal()
{cout << "AbstractAnimal 析构函数调用" << endl;
}class Dog :public AbstractAnimal
{
public:Dog(string name){cout << "Dog 构造函数调用" << endl;m_name = new string(name);}~Dog(){if (m_name != NULL){cout << "Dog 析构函数调用" << endl;delete m_name;m_name = NULL;}}void speak(){cout << *m_name << "  Dog speaking" << endl;}string* m_name;
};void test(void)
{AbstractAnimal* abs = new Dog("Tom");abs->speak();delete abs;
}int main(void)
{test();return 0;
}

推荐文章:[C++核心编程](八):类和对象——继承**

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/538514.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux中mysql的安装、远程访问、基础操作、文件导入

Linux中mysql的安装、远程访问、基础操作、文件导入 cheet card1. 安装1. 使用root账号安装mysql 2. 启动mysql并创建root、管理员两个账号3. 基础操作3.1 数据库的查看、创建、修改、删除3.2 mysql的数据类型3.3 数据表的基本操作3.4 数据表结构的修改3.5 表中数据的增、删、改…

STM32F407_外部中断

这里写目录标题 前言1、EXTI概述2、外部中断配置流程完整代码 前言 注释很详细&#xff0c;放心食用。 1、EXTI概述 STM32F4的每个IO都可以作为外部中断的中断输入口&#xff0c;这点也是STM32F4的强大之处。STM32F407的中断控制器支持22个外部中断/事件请求。每个中断线上都设…

嵌入式常用5种通信协议

简介&#xff1a; 嵌入式常用五种通信协议为&#xff1a;UART、RS232、RS485、IIC、SPI。 由于这几种通信协议十分相似又有区别&#xff0c;所以分组记忆&#xff0c;红色的为一组&#xff0c;蓝色的为一组。 ①组都有两条线&#xff0c;且都是异步通信没得时钟线&#xff0c…

Redis基本使用

Redis基本使用 1.通用命令2.基本数据类型2.1 String2.2 Hash2.3 List2.4 Set2.5 SortedSet 3. SpringDataRedis3.1 简介3.2 快速代码示例3.3 序列化 1.通用命令 针对所有数据类型的操作可以在Redis官方文档查看。以下是通用的命令。 KEYS&#xff1a;查看符合模板的所有key D…

基于boost库的搜索引擎项目

文章目录 一、项目背景二、什么样的搜索引擎三、搜索引擎的宏观图原理四、Parse模块4.1下载boost库源代码4.2提取boost库中以.html为结尾的文件4.2.1 boost库的简单使用 4.3数据清洗(去标签化)4.3.1数据清洗的具体实现 4.4将清洗后的数据写入到raw.txt文件中 五、正排索引 vs 倒…

阿里云服务器租用费用一个月多少钱?5元1个月

阿里云服务器一个月多少钱&#xff1f;最便宜5元1个月。阿里云轻量应用服务器2核2G3M配置61元一年&#xff0c;折合5元一个月&#xff0c;2核4G服务器30元3个月&#xff0c;2核2G3M带宽服务器99元12个月&#xff0c;轻量应用服务器2核4G4M带宽165元12个月&#xff0c;4核16G服务…

了解关键字

关键字 定义&#xff1a;被Java语言赋予了特殊含义&#xff0c;用做专门用途的字符串&#xff08;或单词&#xff09; HelloWorld案例中&#xff0c;出现的关键字有 class、public 、 static 、 void 等&#xff0c;这些单词已经被Java定义好了。 特点&#xff1a;全部关键字都…

运放的基础知识

运算放大器&#xff08;Operational Amplifier&#xff0c;简称运放&#xff09;是一种直流耦合、差模&#xff08;差动模式&#xff09;输入的高增益电压放大器&#xff0c;通常具有单端输出。它能产生一个相对于输入端电势差大数十万倍的输出电势&#xff08;对地而言&#x…

JVM 相关知识点记录

文章目录 前言哪些内存需要回收方法区的垃圾回收垃圾收集算法垃圾收集器年轻代进入老年代条件内存担保机制FullGC 触发时机GC日志解析日志参数 前言 JVM包含内容&#xff1a; 类装载子系统(Class Load SubSystem)运行时数据区(Run-Time Data Areas) 堆栈 局部变量表操作数栈动…

面向对象(精髓)变继承关系为组和关系(_Decorator模式)

在软件开发中&#xff0c;设计模式是解决常见问题的可重用解决方案。在面向对象编程中&#xff0c;继承和组合是两种常用的代码复用方式。然而&#xff0c;随着软件需求的不断变化&#xff0c;我们需要更灵活的设计方式来应对不断变化的需求。在本文中&#xff0c;我们将讨论从…

如何选购自助咖啡机?这三点是关键!

在竞争激烈的咖啡市场中&#xff0c;既有知名咖啡连锁品牌&#xff0c;也有众多咖啡馆和小型连锁店&#xff0c;无人智能饮品机要想在激烈的竞争中脱颖而出&#xff0c;发挥自身优势&#xff1a;快速便捷是关键&#xff0c;同时好的口感才能留客&#xff0c;因此饮品机的选购成…

K8s — PVC|PV Terminating State

在本文中&#xff0c;我们将讨论PV和PVC一直Terminating的状态。 何时会Terminting? 在以下情况下&#xff0c;资源将处于Terminating状态。 在删除Bounded 状态的PVC之前&#xff0c;删除了对应的PV&#xff0c;PV在删除后是Terminting状态。删除PVC时&#xff0c;仍有引用…