超详细的 C++中的封装继承和多态的知识总结<2.多态>

引言

  小伙伴们我们都知道了,什么是封装和继承,在有了这个的基础上我们接着来看什么是多态。多态从字面上意思我们就可以知道,大概就是一个函数的不同形态,而且,前边我们在学习函数重载的时候我们已经简单的了解了如何用一个函数来实现两种不一样的操作。那么本章就会告诉你有关多态性的所有知识,小伙伴们快拿起小本本记好哟。

  好了,废话不多说,小伙伴们,开冲!!!!

多态

什么是多态:

  多态(Polymorphism)是面向对象编程(OOP)中的一个核心概念,它指的是对象可以通过指向其派生类的引用来调用在基类中定义的函数,而且调用的是派生类中重写的方法。

  在面向对象编程中,多态的定义可以概括:同一操作作用于不同的对象时,可以有不同的解释,产生不同的执行结果。 这意味着,同一个方法调用可以在不同的对象上产生不同的行为,这些对象虽然属于不同的类,但是都必须继承自同一个父类或者实现同一个接口。

  我们可以把多态大体分为两种不同的形式:
  那就是静态多态和动态多态

静态多态

  静态多态是通过函数重载和运算符重载实现,其多态性是编译时已经决定的。静态多态的优点是可以提供更好的性能,因为所有的决策都在编译时做出,减少了运行时的开销。

函数重载

有关函数没学明白,没看懂的去看函数专项 》》》点这里看函数专项《《《

  函数重载(Function Overloading)是C++中的一种特性,允许在同一作用域内存在多个同名函数,只要它们的参数列表不同即可。函数的重载可以根据参数的数量、类型或者顺序来区分。

  当调用重载函数时,编译器会根据传递给函数的参数来决定调用哪个函数版本,这个过程称为函数重载解析

函数重载的条件:

  • 相同的函数名:重载的函数必须具有相同的名字。
  • 不同的参数列表:参数列表的不同可以体现在参数的数量、类型或者顺序上。
  • 在同一作用域内:重载的函数必须在同一作用域内,例如同一个类或者同一个全局作用域。
  • 代码示例:
#include <iostream>using namespace std;int myAdd(int a, int b);float myAdd(int a, float b);int main()
{int a1 = 10, a2 = 20;float b1 = 11.1, b2 = 22.2;cout << myAdd(a1, a2) << endl;cout << myAdd(a1, b1) << endl;return 0;
}int myAdd(int a, int b)
{cout << "myAdd(int a, int b)" << endl;return a + b;
}float myAdd(int a, float b)
{cout << "myAdd(int a, float b)" << endl;return a + b;
}

运算符重载

  运算符重载(Operator Overloading)是面向对象编程中的一种特性,它允许开发者对已有的运算符赋予额外的含义,以适应不同的数据类型。这样,用户可以自定义运算符对自定义类型的操作行为。运算符重载使得对象和内置数据类型之间的运算更加自然和直观。

  运算符重载的基本原则是保持原有运算符的基本语义不变。例如,加法运算符 + 通常用于两个数值的相加,重载后也应该表示某种意义上的“相加”操作,而不是彻底改变其行为。

  运算符重载可以通过在类中定义特殊的成员函数来实现,这些函数被称为运算符重载函数。运算符重载函数的名称是由关键字 operator 后跟要重载的运算符符号组成的。

  • 代码示例:
class Complex {
public:double real;double image;Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}// 重载加法运算符 +Complex operator+(const Complex& other) const {return Complex(real + other.real, imag + other.imag);}
};int main() {Complex c1(1.0, 2.0);Complex c2(2.0, 3.0);Complex c3 = c1 + c2; // 使用重载的加法运算符return 0;
}

静态多态代码示例:

#include <iostream>using namespace std;class Cat
{
private:char* m_name;int m_full;
public:Cat(const char* name, int full);~Cat();void eat();//	函数重载产生静态多态void eat(int n);void play();void play(int n);//	运算符重载产生静态多态Cat& operator=(const Cat& cat);void show();
};Cat::Cat(const char* name, int full)
{int len = strlen(name) + 1;m_name = new char[len];strcpy_s(m_name, len, name);m_full = full;
}Cat::~Cat()
{delete[]m_name;
}void Cat::eat()
{cout << m_name << "吃了1条鱼" << endl;m_full++;
}void Cat::eat(int n)
{cout << m_name << "吃了" << n <<"条鱼" << endl;m_full+=n;
}void Cat::play()
{cout << m_name << "抓了1只蝴蝶" << endl;m_full--;
}void Cat::play(int n)
{cout << m_name << "抓了" << n << "只蝴蝶" << endl;m_full -= n;
}Cat& Cat::operator=(const Cat& cat)
{if (this != &cat){delete[]m_name;int len = strlen(cat.m_name) + 1;m_name = new char[len];strcpy_s(m_name, len, cat.m_name);m_full = cat.m_full;		}	return *this;
}void Cat::show()
{cout << m_name << ", " << m_full << endl;
}int main()
{Cat c1("大花", 50);c1.show();c1.play();c1.play(10);c1.show();c1.eat(5);c1.eat();c1.show();Cat c2("二花", 10);c2.show();c2 = c1;c2.show();c1.eat(100);c1.show();c2.show();return 0;
}

虽然静态多态有这样的优点:可以提供更好的性能,因为所有的决策都在编译时做出,减少了运行时的开销。但同时,它也提供了类型安全,因为编译器会检查所有的类型是否匹配。然而,静态多态也缺乏动态性,它不能在运行时根据对象的实际类型来改变行为,这就需要动态多态来实现。

动态多态

  • 在程序运行时,根据指针指向具体对象来调用各自的虚函数,称为动态多态。
  • 成员函数声明时使用virtual关键字修饰的,称为虚函数。
  • 当一个派生类的对象通过基类的指针或引用调用一个虚函数时,会调用与对象类型相对应的函数版本,而不是指针或引用的类型。
  • 动态多态需要满足的三个条件:
    • 基类中定义了虚函数。
    • 子类中重写了基类的虚函数。
    • 基类指针指向子类对象并调用了该虚函数。
      在这里插入图片描述
  • 为了实现动态多态,编译器为每个包含虚函数的类创建一个虚函数表,并为每个对象设置一个虚函数指针(虚指针)指向这个虚函数表。
  • 使用基类指针对虚函数调用时,通过这个虚函数指针,在虚函数表中查找虚函数的地址,从而调用不同的虚函数。
  • 由于包含虚函数的对象有一个虚指针,与没有虚函数的对象相比,含有虚函数的对象指针所占用的内存空间要多。
  • 代码示例:
#include <iostream>using namespace std;class Person
{
public:virtual void buyTicket(){cout << "普通人买全票" << endl;}
};class Student : public Person
{
public:void buyTicket(){cout << "学生可以买学生票" << endl;}
};class Children : public Person
{
public:void buyTicket(){cout << "儿童可以买儿童票" << endl;}
};int main()
{/*父类函数成员声明为虚函数,子类中实现了和父类同名的函数,且父类指针指向子类对象时,通过父类指针调用子类的函数。*/Person person;Student student;Children children;Person* p = NULL;p = &person;p->buyTicket();p = &student;p->buyTicket();p = &children;p->buyTicket();Person* p1[3] = { &person, &student, &children};for (int i = 0; i < 3; i++){p1[i]->buyTicket();}return 0;
}

虚析构函数

  析构函数可以定义为虚函数,如果基类的析构函数定义为虚函数,则派生类的析构函数就会自动称为虚析构函数。

  • 代码示例:
#include <iostream>using namespace std;class Employee
{
protected:char* m_name;
public:Employee(const char* name){cout << "Employee(const char* name) " << name << endl;int len = strlen(name) + 1;m_name = new char[len];strcpy_s(m_name, len, name);}virtual ~Employee(){cout << "~Employee() " << m_name << endl;delete[]m_name;}
};class Teacher : public Employee
{
protected:char* m_course;
public:Teacher(const char* name, const char* course) : Employee(name){cout << "Teacher(const char* name, const char* course) : Employee(name)) " << name << ", " << course << endl;int len = strlen(course) + 1;m_course = new char[len];strcpy_s(m_course, len, course);}~Teacher(){cout << "~Teacher() " << m_name << ", " << m_course << endl;delete[] m_course;}
};int main()
{Teacher* t = new Teacher("王老师", "C++");delete t;/*不使用虚析构函数时,当通过父类指针释放子类对象时,仅调用父类析构函数。*/Employee* e = new Teacher("杨老师", "Python");delete e;
}

纯虚函数函数和抽象类

  • 抽象类就是包含纯虚函数的类。

  • 抽象类不允许实例化,抽象类的指针可以指向实现纯虚函数的子类实例。

  • 如果子类没有实现纯虚函数,子类会继承纯虚函数,并成为一个抽象类。

  • 代码示例:

#include <iostream>using namespace std;//	Person是抽象类,因为包含纯虚函数buyTicket。
class Person
{
public://	定义纯虚函数virtual void buyTicket() = 0;
};class Student : public Person
{
public:void buyTicket(){cout << "学生可以买学生票" << endl;}
};class Children : public Person
{
public:void buyTicket(){cout << "儿童可以买儿童票" << endl;}
};int main()
{//	Person person; 抽象类不能实例化//	Student是Person的子类,实现了Person的纯虚函数buyTicket.Student student;Children children;//	抽象类的指针可以指向其子类对象Person* p = &student;p->buyTicket();p = &children;p->buyTicket();return 0;
}

结语

  小伙伴们,当你看到这里就已经把面向对象的所有知识就全部都学完了,为自己鼓鼓掌,你们是最棒的 ,小杨也是最棒的,小杨会持续不间断的为大家更新新的知识,但同时,大家一定要好好的把前边的好好的复习一遍,而且现在的知识已经够大家在牛客和力扣上边刷相关的题了,大家可以试着去做一做,稍后小杨也会专门开个专题刷题的,内容就是C++相关内容。

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

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

相关文章

[Swiper]在React中使用Swiper时注意销毁实例

swiper版本号&#xff1a; {"swiper": "^4.4.2", }在useEffect中初始化swiper实例&#xff0c;由于依赖项的变更&#xff0c;可能会重复初始化: useEffect(() > {swiper.current new Swiper(#mainSwiper, {autoplay: {delay: 3000,//3秒切换一次},on…

推荐算法学习笔记2.1:基于深度学习的推荐算法-基于共线矩阵的深度推荐算法-AutoRec模型

AutoRec模型 前置知识&#xff1a;推荐算法学习笔记1.1:传统推荐算法-协同过滤算法 AutoRec模型通过引入自编码器结构&#xff0c;将共线矩阵中的用户向量&#xff08;基于用户的U-AutoRec&#xff09;或物品向量&#xff08;基于物品的I-AutoRec&#xff09;嵌入到低维空间后还…

讯方技术鸿蒙应用定制开发服务上架华为云商店

在当前智能化与互联互通发展的时代背景下&#xff0c;鸿蒙操作系统已成为推动创新应用发展的新引擎。随着企业对个性化智能解决方案需求的不断增长&#xff0c;鸿蒙应用定制开发已成为企业技术转型升级的重要途径。 讯方技术作为一家致力于为客户提供全面专业服务的企业&#…

LVM核心概念

1. LVM简介 LVM是逻辑盘卷管理&#xff08;Logical Volume Manager&#xff09;的简称&#xff0c;它是Linux环境下对磁盘分区进行管理的一种机制&#xff0c;LVM是建立在硬盘和分区之上的一个逻辑层&#xff0c;来提高磁盘分区管理的灵活性。 优点&#xff1a; 可以灵活分配…

2024年,精品课录制新方式,站在大屏前录出绿幕抠像的效果!感谢不坑盒子!

先做个小调查&#xff1a;你们那边请工作室录一节课&#xff0c;多少钱&#xff1f;留言区交流一下。 暑假了&#xff0c;老师们又有时间来录课了。 早在2021年秋天&#xff0c;精品课遴选的第一年&#xff0c;我就第一时间给大家分享了2种录精品课的方法&#xff1a;大屏前录…

python源码:opencv多视频源同屏拼接播放

一、前言 如标题所示&#xff0c;这个python代码的目的是利用opencv模块实现多视频源同屏拼接播放的&#xff0c;里面包含视频播放尺寸修改、视频播放加序号、视频流存活检测等方案&#xff0c;可做扩展开发使用。 二、代码 import cv2 import time from func_timeout import …

JAVA里的BigDecimal用法

public class BigDecimaldemo1 {public static void main(String[] args) {System.out.println(0.090.01);//为什么不是0.10呢?} }在使用float或者double类型的数据在进行数学运算的时候&#xff0c;很有可能会产生精度丢失问题。我们都知道计算机底层在进行运算的时候&#x…

科林Linux7_网络爬虫

一、爬虫 网络资源的下载工具&#xff0c;工作与万维网环境&#xff0c;持续获取网页网站中的网络信息。可持续的数据采集机器人 1、搜索引擎技术使用爬虫 2、数据分析、数据挖掘领域&#xff0c;需要爬虫进行数据准备 3、数据批处理、采集&#xff0c;大量获取某些网站中的…

LeetCode题练习与总结:二叉树的前序遍历--144

一、题目描述 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;roo…

数据资产的创新应用与未来展望:探讨数据资产在人工智能、物联网等新兴领域的应用前景,提出前瞻性的数据资产解决方案,为企业探索新的增长点,推动行业创新发展

目录 一、引言 二、数据资产在人工智能领域的应用 1、机器学习与深度学习 2、自然语言处理 3、计算机视觉 三、数据资产在物联网领域的应用 1、智能家居 2、工业物联网 3、智慧城市 四、前瞻性的数据资产解决方案 1、构建统一的数据管理平台 2、加强数据安全和隐私…

基于路径长度的样条插补算法(自动驾驶和路径跟踪控制适用)

以前在做车辆跟踪控制的时候发现在针对有多个X和多个Y对应的路径插补时候&#xff0c;总是报错&#xff0c;因为MATLAB里面的interp1插补函数它要求x要唯一对应一个y&#xff0c;当路径以单独的x或者y来求插补时候的时候就报错。由于在使用Matlab的interp1函数进行插值时&#…

Linux-网络安全私房菜

文章目录 前言入门基本指令篇章字符集设置cdlsdatemkdirtouch-d-m 修改主机名rmshredrename重命名mv移动tar打包与压缩打包但是不压缩打包且压缩更新包文件解压对应的包 zip压缩文件命令cat查看显示行号交互写入&#xff08;追加&#xff09;显示空行 more和lesshead和tailhead…

期末复习---程序填空

注意&#xff1a; 1.数组后移 *p *(p-1) //把前一个数赋值到后一个数的位置上来覆盖后一个数 2.指针找最大字符 max *p while( *p){ if( max< *p) { max*p; qp;/ 用新的指针指向这个已经找到的最大位置&#xff1b;!!!!!!!!! } p; //因为开始没有next &#xff…

Web工程化

1、webpack 1.1 概念 一个前端打包器。 webpack 只识别javascript. 所以需要安装nodejs环境。 1.2 运行环境 Nodejs Nodejs 是运行JavaScript的环境。 因为nodejs发布了许多版本&#xff0c;在不同的技术栈下&#xff0c;需要使用不同的nodejs。 所以需要在电脑上安装n…

web应用技术-第十一次课后作业

验证过滤器进行权限验证的原理。 Filter过滤器&#xff1a;可以把对资源的请求拦截下来&#xff0c;从而实现一些特殊的功能。一般完成登录校验、统一编码处理、敏感字符处理等通用操作。 定义&#xff1a;实现Filter接口 配置&#xff1a;WebFilter(urlPatterns"/*&qu…

常见VPS主机术语有哪些?VPS术语解析

常见VPS主机术语有哪些&#xff1f;本期为大家解析一下我们常见到的听到的VPS专业术语&#xff0c;帮助大家更轻松的了解VPS主机相关知识。 常见VPS主机术语 Apache – 世界上最流行的 Web 服务器软件。 CentOS – 旨在提供基于 Red Hat Enterprise Linux 的企业级操作系统的…

基于springboot+vue+uniapp的超市售货管理平台

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…

考研生活day2--王道课后习题2.3.1、2.3.2、2.3.3

2.3.1 题目描述&#xff1a; 这题和曾经做过的LeetCode203.移除元素一模一样&#xff0c;所以我们就使用LeetCode进行书写&#xff0c;题目链接203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 解题思路 大家的第一反应肯定是根据书上所学的书写方法一样书写&…

【PB案例学习笔记】-26制作一个带浮动图标的工具栏

写在前面 这是PB案例学习笔记系列文章的第26篇&#xff0c;该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习&#xff0c;提高编程技巧&#xff0c;以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码&#xff0c;小凡都上传到了gite…

爬虫cookie是什么意思

“爬虫 cookie”指的是网络爬虫在访问网站时所使用的cookie&#xff0c;网络爬虫是一种自动化程序&#xff0c;用于在互联网上收集信息并进行索引&#xff0c;这些信息可以用于搜索引擎、数据分析或其他目的。 本教程操作系统&#xff1a;Windows10系统、Dell G3电脑。 “爬虫…