超详细的 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.mfbz.cn/a/763088.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

企业源代码加密软件丨透明加密技术是什么

在一个繁忙的软件开发公司中&#xff0c;两位员工小李和小张正在讨论源代码安全的问题。 “小张&#xff0c;你有没有想过我们的源代码如果被泄露了怎么办&#xff1f;”小李担忧地问。 “是啊&#xff0c;这是个大问题。源代码是我们的核心竞争力&#xff0c;一旦泄露&#…

最短路算法三

图论三 20240624 算法实用主义&#xff0c;用到再学 1. 大纲&#xff1a; a. 最小生成树都是无向图 难在建图&#xff0c;不考原理&#xff0c;重点记思路&#xff08;是骨头&#xff09;&#xff0c;自己复述一遍&#xff0c;不能死记代码 血肉 类似最短路 prim&#xff08;…

web基础以及http协议

web基础介绍 web&#xff1a;就是我们所说的网页&#xff0c;打开网站展示的页面。&#xff08;全球广域网&#xff0c;万维网&#xff09; world wide web &#xff08;www&#xff09; 分布式图形信息系统 分布式&#xff1a;计算机系统或者是应用程序分布在多台独立的计算…

探索智慧校园人事系统,了解人事合同功能的核心优势

智慧校园人事系统中的人事合同管理功能&#xff0c;是一个高度集成且自动化的模块&#xff0c;专注于优化合同的全生命周期管理&#xff0c;从合同创建、审批、签署到存档及续签提醒&#xff0c;旨在提升人事管理工作的规范性与效率&#xff0c;同时保障学校的法律合规性。 在智…

微信小程序-插槽slot

一.插槽slot 在页面使用自定义组件的时候&#xff0c;如果在自定义组件里面写子组件&#xff0c;子组件的内容无法显示。 <custom01> <text slotslot-top>你好&#xff0c;上方组件</text> 你好&#xff0c;组件 <text slotslot-bottom>你好&#xf…

数据结构 - C/C++ - 栈

目录 结构特性 结构实现 结构容器 结构设计 顺序栈 链式栈 结构特性 栈(stack)是线性表的一种形式&#xff0c;限定仅在表的一端进行插入或者删除的操作。 栈顶 - 表中允许插入、删除的一端称为栈顶(top)&#xff0c;栈顶位置是可以发生变化的。 插入 - 进栈、入栈、压栈…

蒂升电梯职业性格和Verify认知能力SHL测评答题攻略及薪资待遇解密!

​一、蒂升电梯职业性格和认知能力测评考什么 您好&#xff01;蒂升电梯公司邀请您参加的OPQ职业性格测评和Verify认知能力测评是两种常见的评估工具&#xff0c;用于帮助了解个人的职场性格特点和认知能力。 OPQ职业性格测评 这是一种性格测试&#xff0c;通常用于评估个人在…

APP逆向 day8 JAVA基础3

一.前言 昨天我们讲了点java基础2.0&#xff0c;发现是又臭又长&#xff0c;今天就是java基础的最后一章&#xff0c;也就是最难的&#xff0c;面向对象。上一末尾也是提到了面向对象&#xff0c;但是面向对象是最重要的&#xff0c;怎么可能只有这么短呢&#xff1f;所以今天…

人工智能——常用数学基础之线代中的矩阵

1. 矩阵的本质&#xff1a; 矩阵本质上是一种数学结构&#xff0c;它由按照特定规则排列的数字组成&#xff0c;通常被表示为一个二维数组。矩阵可以用于描述一组数据&#xff0c;或者表示某种关系&#xff0c;比如线性变换。 在人工智能中&#xff0c;矩阵常被用来表示数据集…

技术革新:如何用数据中台实现数字化转型

作为程序员&#xff0c;我们总是对技术如何改变企业运作充满好奇。今天&#xff0c;我们将深入探讨森马集团如何利用数据中台技术&#xff0c;实现从传统数据分析到数字化转型的华丽转身。 1. 技术背景&#xff1a;森马集团的数字化挑战 森马集团&#xff0c;一个在服饰行业占…

SpringCloud_Ribbon负载均衡

概述 SpringCloud底层其实是利用了一个名为Ribbon的组件&#xff0c;来实现负载均衡功能的。 源码 LoadBalancerInterceptor 其中含有intercept方法&#xff0c;拦截用户的HttpRequest请求&#xff1a; request.getURI() 获取请求uri&#xff0c;即http://userservice/use…

解析QAnything启动命令过程

一.启动命令过程日志 启动命令bash ./run.sh -c local -i 0 -b hf -m Qwen-1_8B-Chat -t qwen-7b-chat。输入日志如下所示&#xff1a; rootMM-202203161213:/mnt/l/20230918_RAG方向/QAnything# bash ./run.sh -c local -i 0 -b hf -m Qwen-1_8B-Chat -t qwen-7b-chat From …

Spring Boot如何集成Spring Security?

&#x1f345; 作者简介&#xff1a;哪吒&#xff0c;CSDN2021博客之星亚军&#x1f3c6;、新星计划导师✌、博客专家&#x1f4aa; &#x1f345; 哪吒多年工作总结&#xff1a;Java学习路线总结&#xff0c;搬砖工逆袭Java架构师 &#x1f345; 技术交流&#xff1a;定期更新…

1-3.文本数据建模流程范例

文章最前&#xff1a; 我是Octopus&#xff0c;这个名字来源于我的中文名–章鱼&#xff1b;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github &#xff1b;这博客是记录我学习的点点滴滴&#xff0c;如果您对 Python、Java、AI、算法有兴趣&#xff0c;可以关注我的…

算法笔记:模拟过程(螺旋遍历矩阵)

1 模拟过程 “模拟过程题”通常指的是那些要求编程者通过编写代码来“模拟”或重现某个过程、系统或规则的题目。这类题目往往不涉及复杂的数据结构或高级算法&#xff0c;而是侧重于对给定规则的精确执行和逻辑的清晰表达。 其中螺旋遍历矩阵的题目就是一类典型的模拟过程题…

代码随想录-Day44

322. 零钱兑换 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1 。 你可以认为每种硬币的数…

ARCGIS python 裁剪栅格函数 arcpy.management.Clip

ARCGIS python 裁剪栅格函数 arcpy.management.Clip 1 功能 裁剪掉栅格数据集、镶嵌数据集或图像服务图层的一部分。 2 使用情况 基于模板范围提取部分栅格数据集&#xff0c;输出与模板范围相交的所有像素使用以 x 和 y 坐标的最小值和最大值确定的包络矩形或使用输出范围文…

商汤上海AI实验室联合发布:自动驾驶全栈式高精度标定工具箱(含车、IMU、相机、激光雷达等的标定)

前言 在自动驾驶技术飞速发展的今天&#xff0c;传感器的精确标定对于确保系统性能至关重要。SensorsCalibration&#xff0c;一个专为自动驾驶车辆设计的标定工具箱&#xff0c;提供了一套全面的解决方案&#xff0c;用于校准包括IMU、激光雷达、摄像头和雷达在内的多种传感器…

Evented PLEG: iSulad 稳态 CPU 利用率降低30%的关键特性

背景 容器技术在不断发展的过程中&#xff0c;已被广泛应用于多种场景。OpenAtom openEuler&#xff08;简称"openEuler"&#xff09; 社区容器引擎项目 iSulad[1]面向 CT、IT 领域的不同需求而生&#xff0c;它具有轻量级、高性能的特点&#xff0c;可以在资源受限…

vue3引入本地静态资源图片

一、单张图片引入 import imgXX from /assets/images/xx.png二、多张图片引入 说明&#xff1a;import.meta.url 是一个 ESM 的原生功能&#xff0c;会暴露当前模块的 URL。将它与原生的 URL 构造器 组合使用 注意&#xff1a;填写自己项目图片存放的路径 /** vite的特殊性…