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

C++入门——多态

目录

多态的概念

多态的定义以及实现

多态的构成条件

虚函数

虚函数的重写/覆盖

虚函数重写的一些其他问题

协变

析构函数的重写

override和final关键字

纯虚函数和抽象类


多态的概念

多态通俗来说就是多种形态。多态分为编译时多态(静态多态)和运行时多态(动态多态)。

静态多态就是我们之前讲的函数重载和函数模版,传不同类型的参数就可以调用不同的函数,通过参数不同达到多种形态。之所以叫做编译时多态,是因为他们实参传给形参的参数匹配是在编译时完成的。

动态多态,就是去完成某个行为,可以传不同的对象就会完成不同的行为。例如都是买票,普通人买票就是全价买票;学生买票就是打折。

多态的定义以及实现

多态的构成条件

多态是一个继承关系下的类对象,去调用同一函数,产生了不同的行为。

实现多态还必须有两个重要条件:

  • 必须是基类的指针或者引用调用虚函数。

因为只有基类的指针或者引用才能既指向基类对象又指向派生类对象。

  • 被调用的函数必须是虚函数,并且完成了虚函数重写/覆盖。

只有完成虚函数的重写/覆盖,基类和派生类之间才能有不同的函数,多态的不同类型效果才能达到。

#include<iostream>
using namespace std;
class person
{
public:virtual void buytic(){cout<<"全价"<<endl;}
};
class student:public person 
{
public:virtual void buytic(){cout<<"打折"<<endl;}};
void func(person& p){p.buytic();}
int main()
{person p;student s;func(p);func(s);return 0;
}

虚函数

类成员函数前面加virtual修饰,那么这个成员函数被称为虚函数。注意:非成员函数不能加virtual修饰。

class person
{
public:virtual void buytic(){cout<<"全价"<<endl;}
};

虚函数的重写/覆盖

  • 虚函数的重写/覆盖:派生类中有一个跟基类完全相同的虚函数。要求三同:即返回值类型,函数名字,参数列表相同。
  • 如果派生类不重写基类的虚函数,则会直接继承并使用基类的虚函数实现。
  • 重写可以被当做函数内容的重写!!

注意:在重写虚函数时,派生类的虚函数不加virtual关键字时也可以构成重写,但这种写法不是很规范,不建议用。

猜猜下面的代码输出的结果是什么:

class A
{
public:virtual void func(int val = 1){ std::cout<<"A->"<< val <<std::endl;}virtual void test(){ func();}
};
class B : public A
{
public:void func(int val = 0){ std::cout<<"B->"<< val <<std::endl; }
};
int main(int argc ,char* argv[])
{B*p = new B;p->test();return 0;
}

结果是:

是不是很惊讶,原因是:

虚函数重写的一些其他问题

协变

派生类重写基类虚函数时,与基类虚函数返回值不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的引用或者指针时成为协变。

class person
{
public:virtual person* buytic(){cout << "全价" << endl;return nullptr;}void func(){buytic();}};
class student :public person
{
public:virtual student* buytic(){cout << "打折" << endl;return nullptr;}};
int main()
{person p;student s;p.func();s.func();return 0;
}

析构函数的重写

基类的析构函数为虚函数,此时派生类虚构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写。

虽然基类和派生类的析构函数名字不一样,看起来不符合重写的规则,实际上编译器对析构函数的名称做了特殊处理,都统一处理成了~destructor。

知识回顾

delete的原理:

1.在空间上执行析构函数,完成对象中资源的清理工作。

2.再用operator delete函数释放对象的空间。

class person
{
public://virtual~person(){cout << "~person()" << endl;}
};
class student :public person
{
public:~student(){cout << "~student()" << endl;}
};
int main()
{person* p=new person;person* s=new student;delete p;//~person+delete pdelete s;return 0;
}

如果不加virtual的话,可以看出只析构了student类中person的部分,会造成内存泄漏。但是加上virtual的话,我们就没有这个烦恼了。

override和final关键字

  • override:可以帮助用户检测虚函数是否重写

当我们不小心拼写错误时,编译器并不能直接检查出来,加上override皆可以检测出来了。

  • final:我们不想让派生类重写虚函数时可以用。

纯虚函数和抽象类

  • 纯虚函数:在虚函数的后面写上=0,这个函数就是纯虚函数了。
virtual void  buytic()=0
{cout << "全价" << endl;}
  • 抽象类:包含纯虚函数的类叫做抽象类。

抽象类不能实例化出对象,所以在某种程度上也强制了派生类重写虚函数。因为不重写,派生类也是抽象类,不能实例化出对象

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

相关文章:

  • 用数据绘图(1):用 Highcharts 打造你的数据艺术世界
  • Hadoop面试题及详细答案 110题 (96-105)-- Hadoop性能优化
  • 监控系统理论与实践:从认知到Zabbix入门
  • ROS 传感器模块的通用架构设计与跨中间件扩展实践
  • 措美网站建设游戏网站开发名字
  • openwrt 环境安装
  • iis 发布网站内部服务器错误东莞沙田门户网站建设
  • 订单 API 接口调试常见问题排查:3 类高频问题 + 落地解决方案
  • JavaWeb--使用JDBC操作数据库(一)
  • 【Web开发】待办事项列表
  • Linux IIO研究(二)
  • 浙江建设厅网站那三类人员爱给网官网免费素材
  • Spring Boot整合Apache Shiro权限认证框架(实战篇)
  • Rust 错误处理
  • 【在 Windows 上运行 Apache Hadoop 或 Spark/GeoTrellis 涉及 HDFS 】
  • Linux操作系统-命令行参数及环境变量
  • 系统架构设计师备考第40天——软件可靠性基础
  • RAG 问题处理系统架构解析:企业级智能问答QuestionsProcessor.py的工程实现
  • LlamaIndex多模态RAG开发实现详解
  • springboot实现微信小程序支付(服务商和普通商户模式)
  • 石景山网站建设好的公司有特色的企业网站
  • 个人建网站怎么赚钱网站一般用什么数据库
  • 【机器学习03】学习率与特征工程、多项式回归、逻辑回归
  • PyTorch解析使用张量与动态计算图实现深度学习模型的高效训练
  • 大二java学习笔记:二维数组
  • 缓存行Cache Line
  • 10-机器学习与大模型开发数学教程-第1章 1-2 O(n) 表示法与时间复杂度
  • toLua[六] Examples 05_LuaCoroutine分析
  • keil5使用STlink下载程序到stm32后不自动运行的解决办法
  • stm32大项目阶段20251015