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

news2024/10/4 0:30:08

引言

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

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

多态

什么是多态:

  多态(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.coloradmin.cn/o/1883693.html

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

相关文章

如何优化前端性能:提高网页加载速度的实用技巧

我们在前端开发中&#xff0c;性能优化是提高用户体验的关键因素。网页加载速度直接影响用户的满意度和留存率。本文将介绍几种优化前端性能的实用方法&#xff0c;帮助你提高网页加载速度。 问题描述 &#xff1a; 首先前端性能优化涉及多个方面&#xff0c;包括减少HTTP请…

【单片机与嵌入式】stm32串口通信入门

一、串口通信/协议 &#xff08;一&#xff09;串口通信简介 串口通信是一种通过串行传输方式在电子设备之间进行数据交换的通信方式。它通常涉及两条线&#xff08;一条用于发送数据&#xff0c;一条用于接收数据&#xff09;&#xff0c;适用于各种设备&#xff0c;从微控制…

万字长文|下一代系统内存数据加速接口SDXI解读

本文内容分为5章节&#xff0c;总计10535字&#xff0c;内容较多&#xff0c;建议先收藏&#xff01; 1.SDXI技术产生的背景 2.SDXI相比DMA的优势 3.SDXI实现原理与架构 3.1 描述符环原理解读 3.2 上下文管理介绍 3.3 AKey与RKey解读 3.4 错误日志和状态管理 3.5 跨Function访…

javascript 常见设计模式

什么是设计模式? 在软件开发中&#xff0c;设计模式是解决特定问题的经验总结和可复用的解决方案。设计模式可以提高代码的复用性、可维护性和可读性&#xff0c;是提高开发效率的重要手段。 单例模式 1.概念 单例模式 &#xff08;Singleton Pattern&#xff09;&#xf…

c++ 智能指针实战分析

一.智能指针的设计思路 智能指针是类模板&#xff0c;再栈上创建智能指针对象。把普通指针交给智能指针对象。智能指针对象过期时&#xff0c;调用析构函数释放普通指针的内存。 智能指针的类型 auto_ptr是C98的标准&#xff0c;c17已经弃用。unique_ptr、shared_ptr和weak_…

动手学深度学习(Pytorch版)代码实践 -计算机视觉-41目标检测数据集

41目标检测数据集 import os import pandas as pd import torch import torchvision import matplotlib.pylab as plt from d2l import torch as d2l# 数据集下载链接 # http://d2l-data.s3-accelerate.amazonaws.com/banana-detection.zip# 读取数据集 #save def read_data_b…

Mustango——音乐领域知识生成模型探索

Mustango&#xff1a;利用领域知识的音乐生成模型 论文地址&#xff1a;https://arxiv.org/pdf/2311.08355.pdf 源码地址&#xff1a;https://github.com/amaai-lab/mustango 论文题为**“**利用音乐领域知识开发文本到音乐模型’Mustango’”。它利用音乐领域的知识从文本指…

计算机毕业设计Python深度学习美食推荐系统 美食可视化 美食数据分析大屏 美食爬虫 美团爬虫 机器学习 大数据毕业设计 Django Vue.js

Python美食推荐系统开题报告 一、项目背景与意义 随着互联网和移动技术的飞速发展&#xff0c;人们的生活方式发生了巨大变化&#xff0c;尤其是餐饮行业。在线美食平台如雨后春笋般涌现&#xff0c;为用户提供了丰富的美食选择。然而&#xff0c;如何在海量的餐饮信息中快速…

python 笔试面试八股(自用版~)

1 解释型和编译型语言的区别 解释是翻译一句执行一句&#xff0c;更灵活&#xff0c;eg&#xff1a;python; 解释成机器能理解的指令&#xff0c;而不是二进制码 编译是整个源程序编译成机器可以直接执行的二进制可运行的程序&#xff0c;再运行这个程序 比如c 2 简述下 Pyth…

2.2章节python的变量和常量

在Python中&#xff0c;变量和常量有一些基本的概念和用法&#xff0c;但需要注意的是&#xff0c;Python本身并没有内置的“常量”类型。然而&#xff0c;程序员通常会遵循一种约定&#xff0c;即使用全部大写的变量名来表示常量。 一、变量 在Python中&#xff0c;变量是一…

对不起,AI大模型不是风口

“我们正处在全新起点&#xff0c;这是一个以大模型为核心的人工智能新时代&#xff0c;大模型改变了人工智能&#xff0c;大模型即将改变世界。”——5月26日&#xff0c;百度创始人、董事长兼CEO李彦宏先生在2023中关村论坛发表了《大模型改变世界》演讲。 李彦宏指出&#…

4PCS点云配准算法实现

4PCS点云配准算法的C实现如下&#xff1a; #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/common/common.h> #include <pcl/common/distances.h> #include <pcl/common/transforms.h> #in…

PostgreSQL介绍与安装

一、PostgreSQL数据库介绍 1、什么是数据库&#xff1f; 数据库&#xff08;Database&#xff09;是按照数据结构来组织、存储和管理数据的仓库。每个数据库都有一个或多个不同的 API 用于创建&#xff0c;访问&#xff0c;管理&#xff0c;搜索和复制所保存的数据。 我们也…

JAVA医院绩效考核管理系统源码:系统优势、系统目的、系统原则 (自主研发 功能完善 可直接上项目)

JAVA医院绩效考核管理系统源码&#xff1a;系统优势、系统目的、系统原则 &#xff08;自主研发 功能完善 可直接上项目&#xff09; 医院绩效考核系统优势 1.实现科室负责人单独考核 对科室负责人可以进行单独考核、奖金发放。 2. 科室奖金支持发放到个人 支持奖金二次分配&…

同一个excel表格,为什么在有的电脑上会显示#NAME?

一、哪些情况会产生#NAME?的报错 1.公式名称拼写错误 比如求和函数SUM&#xff0c;如果写成SUN就会提示#NAME&#xff1f;报错。 2.公式中的文本值未添加双引号 如下图&#xff1a; VLOOKUP(丙,A:B,2,0) 公式的计算结果会返回错误值#NAME?&#xff0c;这是因为公式中文本…

GraphPad Prism生物医学数据分析软件下载安装 GraphPad Prism轻松绘制各种图表

Prism软件作为一款功能强大的生物医学数据分析与可视化工具&#xff0c;其绘图功能尤为突出。该软件不仅支持绘制基础的图表类型&#xff0c;如直观明了的柱状图、展示数据分布的散点图&#xff0c;以及描绘变化趋势的曲线图&#xff0c;更能应对复杂的数据呈现需求&#xff0c…

7-1作业

1.实验目的&#xff1a;完成字符收发 led.h #ifndef __GPIO_H__ #define __GPIO_H__#include "stm32mp1xx_rcc.h" #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_uart.h"//RCC,GPIO,UART初始化 void init();//字符数据发送 void set_tt…

【2024 插件开发大赛】为 ONLYOFFICE 开发插件,赢取万元奖金!

我们发布了 2024 插件开发大赛&#xff1a;为 ONLYOFFICE 开发适合中国用户的插件&#xff0c;赢取税前5500 – 10000元的结项奖金与证书&#xff01;阅读本文了解详情。 关于 ONLYOFFICE ONLYOFFICE 是一个国际开源项目&#xff0c;由领先的 IT 公司 Ascensio System SIA 开发…

论坛万能粘贴手(可将任意文件转为文本)

该软件可将任意文件转为文本。 还原为原文件的方法&#xff1a;将得到的文本粘贴到记事本&#xff0c;另存为UUE格式&#xff0c;再用压缩软件如winrar解压即可得到原文件。建议用于小软件。 下载地址&#xff1a;https://download.csdn.net/download/wgxds/89505015 使用演示…

算法基础入门 - 2.栈、队列、链表

文章目录 算法基础入门第二章 栈、队列、链表2.1 队列2.2 栈2.3 纸牌游戏2.4 链表如何建立链表?1.我们需要一个头指针(head)指向链表的初始。链表还没建立时头指针head为空2.建立第一个结点3.设置刚创建的这个结点的数据域(左半)和指针域(右半)4.设置头指针,头指针可方便…