C++的面向对象学习(6):运算符的重载

文章目录

  • 前言:什么是运算符重载?针对自定义的类与对象类型。
  • 一、加号的运算符重载
    • 1.引入背景
    • 2.所以运算符重载的作用:
    • 3.实现对象间的相加代码:+号运算符重载
      • ①在类中实现加号运算符重载
      • ②设计全局函数实现加号运算符重载
      • ③改写函数,实现对象与数值之间的相加
  • 二、左移与右移的运算符重载
    • 1.引入背景
    • 2.成员函数实现左移运算符重载
      • ①全局函数实现左移重载
      • ②成员变量一般是私有的,无法让全局函数访问,怎么办呢?
  • 三、递增运算符++的重载
    • 1.引入背景
    • 2.对成员变量实现前置递增和后置递增
  • 四、赋值运算符=的重载
    • 1.引入背景
    • 2.代码实现
  • 五、关系运算符(>、<、==、!=)的重载
    • 1.引入背景
    • 2.代码实现
  • 六、函数调用运算符()的重载
    • 1.背景引入
    • 2.代码例子:


前言:什么是运算符重载?针对自定义的类与对象类型。

运算符重载是C++中一种强大的特性,它允许我们为自定义的类类型定义运算符的行为。通过运算符重载,我们可以使用自定义的类对象像使用内置类型一样进行运算。

以下是一些常见的运算符重载示例:

算术运算符重载:+、-、*、/等运算符可以被重载,使得两个对象可以进行相应的运算。

关系运算符重载:==、!=、<、>、<=、>=等运算符可以被重载,用于比较两个对象的关系。

赋值运算符重载:=运算符可以被重载,用于将一个对象的值赋给另一个对象。

下标运算符重载:[]运算符可以被重载,用于实现类似数组的下标访问操作。

函数调用运算符重载:()运算符可以被重载,使得对象可以像函数一样被调用。

输入输出运算符重载:<<和>>运算符可以被重载,用于实现对象的输入和输出。

一、加号的运算符重载

1.引入背景

在这里插入图片描述
在这里插入图片描述
如果我想实现两个对象相加后,对应的变量之和等于第三个对象的该变量,直接相加肯定是不行的,会报错。
如果用常规的:
在这里插入图片描述
可以到是可以,但是如果人很多,从p1、p2、p3、…p100,我们想求出其总和放到一个对象中去,或者涉及很多字符串型变量的拼接,根本不可能一一写出来。另外,如果想用for循环来做累加操作也不行,因为对象名没有所谓的序号,不能用i来代替每一个对象。所以这就体现出运算符重载的作用了。

2.所以运算符重载的作用:

让类的对象这一特殊的类型,也具有加减乘除、赋值、比较、数组化的能力。

3.实现对象间的相加代码:+号运算符重载

①在类中实现加号运算符重载

class person {
public:
    int age;
    int money;

    person operator+(const person& other) {
        person result;
        result.age = this->age + other.age;
        result.money = this->money + other.money;
        return result;
    }
};

(1)在类中重载加法运算符时,我们定义了一个名为operator+的成员函数。这个函数接受一个person对象的引用作为参数,表示要与当前对象相加的另一个对象。函数体内,创建了一个新的person对象result,用于存储相加的结果。然后将当前this指针指向的对象的年龄和另一个对象的年龄相加,并将结果赋值给result对象的年龄成员变量。
最后,返回result对象就实现了将两个person对象的年龄和钱相加,并将结果作为新的person对象返回。

(2)通过自己写成员函数,就实现了两个对象的各个属性相加后返回新的对象功能。

(3)operator+是什么?
就是一个函数名称,这是person类的成员函数。在主函数中,我们可以这样调用:

int main()
{
	person p1;
	p1.age = 15;
	p1.money = 1000;
	person p2;
	p2.age = 18;
	p2.money = 1500;

	//想实现第三个对象p3的年龄和钱是p1p2的加和
	person p3 = p1.operator+(p2);

	
	system("pause");
}

但是编译器很聪明,他看到operator+这个形式,便可以直接简化理解成:

//想实现第三个对象p3的年龄和钱是p1p2的加和
	person p3 = p1+p2;

在重载的加法运算符函数中,关键字 this 指向当前对象,也就是 p1。而参数 other 则指向传递进来的对象,也就是 p2。在函数内部,this 指向 p1,other 指向 p2。

②设计全局函数实现加号运算符重载

person operator+(person& p1, person& p2) {
	person res;
	res.age = p1.age + p2.age;
	res.money = p1.money + p2.money;
	return res;
}

int main()
{
	person p1;
	p1.age = 15;
	p1.money = 1000;
	person p2;
	p2.age = 18;
	p2.money = 1500;

	//全局函数的加号重载调用
	person p4 = p1 + p2;
	system("pause");
}

③改写函数,实现对象与数值之间的相加

//实现一个对象与常数相加的重载
person operator+(person& p1, int num) {
	person val;
	val.age = p1.age + num;
	val.money = p1.money + num;
	return val;
}

二、左移与右移的运算符重载

1.引入背景

常规的左移运算符 << 和右移运算符 >> 是 C++ 中的位运算符,用于对流对象进行输入和输出操作。它们也可以被重载以实现自定义的输入和输出行为。

string myname="xiaoming";
cout<<"hello world"<<myname<<endl;
int val;
cin>>val;

现在我有个需求,对于一个类的对象:
在这里插入图片描述

person p1;
p1.age=18;
p1.money=5000;
cout<<p<<endl;

我想让cout可以直接输出p的所有成员属性,显然目前的语法规则是不允许的,我们只能单独一项一项的打印输出。
重载左移运算符 << 可以用于 自定义对象 的输出操作,使其能够以自定义的方式输出到流对象中。重载右移运算符 >> 则可以用于 自定义对象 的输入操作,使其能够以自定义的方式从流对象中读取数据。

2.成员函数实现左移运算符重载

①全局函数实现左移重载

在这里插入图片描述

如果把cout和对象p作为函数的两个传参的话,那首先得明确cout到底是个什么类型的变量?

cout 是 C++ 标准库中的一个对象,它是 std::ostream 类型的变量。std::ostream 是一个输出流类,用于将数据输出到不同的目标,比如控制台、文件等。
cout 对象是 std::ostream 类的一个实例,它定义了一系列的成员函数,如 operator<<,用于将不同类型的数据输出到流中。通过使用 << 运算符,我们可以将数据插入到 cout 流中,并将其输出到标准输出设备(通常是控制台)。

在这里插入图片描述
osteam是输出流类的一个对象,全局只有一个,用引用传值。

//实现一个对象与cout的左移运算符重载
ostream& operator<<(ostream& out, person& p) {

	out << p.age << endl;
	out << p.money << endl;
	return out;
}

out是类ostream的引用对象,把结果又引用返回给cout这个唯一的对象。

②成员变量一般是私有的,无法让全局函数访问,怎么办呢?

上一节说了,想让函数访问私有成员变量,有很多办法。
首先可以在类里面写函数接口,但是变量多起来就比较麻烦。

另外就是使用友元声明。可以直接用friend声明友元类或者友元全局函数,就可以直接访问私有变量了。而友元类的成员函数去访问另一个类的私有变量上次编译器总是报错,就不推荐了。

class person{
friend ostream& operator<<(ostream& out, person& p);
private:
	int a;
	int b;
public:
	person(int x,int y){
		a=x;
		b=y;
	}
}

//实现一个对象与cout的左移运算符重载
ostream& operator<<(ostream& out, person& p) {

	out << p.age1 << endl;
	out << p.money1 << endl;
	return out;
}

int main(){
	person p1(1,2);
	cout<<p1<<endl;
}

三、递增运算符++的重载

1.引入背景

实现:实例化一个对象后,可以直接对该对象进行前置++和后置++的操作。

person p1;
p1++;
++p1;

2.对成员变量实现前置递增和后置递增

class Counter {
public:
    Counter() : count(0) {}
    // 前置递增运算符
    Counter& operator++() {
        ++count;
        return *this;
    }

    // 后置递增运算符
    Counter operator++(int) {
        Counter temp = *this;
        ++count;
        return temp;
    }

private:
    int count;
};

前置递增运算符(++)重载函数返回一个引用,它将计数器的值加1,并返回自身的引用。这样,我们可以使用前置递增运算符来直接对计数器对象进行递增操作。

后置递增运算符(++)重载函数接受一个额外的int参数(通常不使用),用于区分前置递增和后置递增。它首先创建一个临时的Counter对象temp,将当前计数器的值赋给temp,然后将计数器的值加1,并返回temp对象。这样,我们可以使用后置递增运算符来对计数器对象进行递增操作,同时还可以获取递增前的值。
主程序里:

Counter counter;
++counter;  // 前置递增
int previousValue = counter++;  // 后置递增,并获取递增前的值

四、赋值运算符=的重载

1.引入背景

实现:实例化两个对象后,可以直接让第二个对象赋值给第一个对象。

person p1;
person p2;
p2=p1;

2.代码实现

	//赋值运算符重载
	person& operator=(const person& other) {
		if (this != &other) {
			count = other.count;
		}
		return *this;
	}

person& operator=(const person& other): 这是赋值运算符重载函数的声明,它指定了函数的返回类型为person&,表示返回一个对当前对象的引用。参数other是一个常量引用,表示要赋值的另一个person对象。

if (this != &other): 这是一个条件判断语句,用于检查是否是自我赋值。this是指向当前对象的指针,&other是指向另一个对象的指针。如果它们不相等,说明不是自我赋值,可以进行赋值操作。

count = other.count;: 这行代码将另一个对象other的count成员变量的值赋给当前对象的count成员变量。这是一个简单的赋值操作,用于复制对象的状态。

return this;: 这行代码返回对当前对象的引用,以支持链式赋值操作。通过返回this,可以允许连续多次赋值,例如p1 = p2 = p3;。

五、关系运算符(>、<、==、!=)的重载

1.引入背景

要实现对象的关系比较

person p1;
person p2;

p1>p2;
p1==p2;
p1!=p2;

2.代码实现

class person {
public:
    // 构造函数和其他成员函数的实现
	person(int a):count(a){}

    bool operator>(const person& other) const {
        if(this->count > other.count){
        	return true;
        }
        else return false;
    }

    bool operator<(const person& other) const {
        return count < other.count;
    }

    bool operator==(const person& other) const {
        return count == other.count;
    }

    bool operator!=(const person& other) const {
        return count != other.count;
    }

private:
    int count;
    // 其他成员变量
};
 
int main(){
	person p1(2);
	person p2(5);

// 使用关系运算符进行比较
if (p1 > p2) {
    // p1的count大于p2的count
} else if (p1 < p2) {
    // p1的count小于p2的count
} else if (p1 == p2) {
    // p1的count等于p2的count
} else {
    // p1的count不等于p2的count
}
}

六、函数调用运算符()的重载

1.背景引入

函数调用运算符的重载常常用于创建仿函数(Functor)。仿函数是一种行为类似于函数的对象,可以像函数一样被调用。

2.代码例子:

下面是一个示例,展示了如何创建一个简单的仿函数:

class Adder {
public:
    int operator()(int x, int y) const {
        return x + y;
    }
};

int main() {
    Adder add;
    int result = add(3, 4); // 调用仿函数
    // result 等于 7
    return 0;
}

在上述示例中,我们定义了一个名为Adder的类,并在其中重载了函数调用运算符()。在重载函数中,我们将两个整数相加,并返回结果。

在main函数中,我们创建了一个Adder对象add,并使用add(3, 4)的语法来调用仿函数。这将返回3 + 4 = 7的结果,并将其存储在result变量中。

仿函数可以像函数一样接受参数,并返回结果。它们可以用于算法函数、STL容器和其他需要函数对象的场景。

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

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

相关文章

基于QListWidget的多段曲线展示器

目录 1 开发背景 2 创建程序 3 更改main window函数 4 测试构造函数 5 文件打开函数 6 拖放的实现 1 开发背景 由于视图控件的拖放逻辑比较难&#xff0c;需要同时子类化视图和模型&#xff0c;那么对于小数据而言&#xff0c;不如使用便捷类。因此&#xff0c;决定对多…

JavaOOP篇----第十八篇

系列文章目录 文章目录 系列文章目录前言一、什么是成员内部类二、Static Nested Class 和 Inner Class的不同三、什么时候用assert四、Java有没有goto前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女…

探索音乐创作的新境界——PreSonus Studio One Pro 6

音乐是人类情感的表达方式之一&#xff0c;而音乐制作编曲软件则是让人们将创意转化为音乐作品的重要工具之一。在众多软件中&#xff0c;PreSonus Studio One Pro 6凭借其强大的功能和出色的用户体验&#xff0c;成为了许多音乐制作人的首选。 首先&#xff0c;PreSonus Stud…

App应用如何在应用市场获得更多下载量?

App的转化率至关重要&#xff0c;App如何获得更多用户&#xff0c;提高应用的下载量&#xff1f; 据 Apple 称&#xff0c;每周有 6.5亿访问者访问应用商店&#xff0c;77%的应用下载来自 iOS 应用商店的自然搜索。随着 Apple 默认关闭了IDFA&#xff0c;自然搜索比以往任何时…

git之UGit可视化工具使用

一、下载安装UGit 链接&#xff1a;https://pan.baidu.com/s/1KGJvWkFL91neI6vAxjGAag?pwdsyq1 提取码&#xff1a;syq1 二 、使用SSH进行远程仓库连接 1.生成SSH密钥 由于我们的本地 git仓库和 gitee仓库之间的传输是通过SSH加密的&#xff0c;所以我们需要配置SSH公钥。才…

结合教学经验谈计量经济学与Stata软件的学习

1.经济金融专业学生计量学习之痛 教学实践中&#xff0c;很多学生跟我抱怨计量经济学难学的问题&#xff0c;也有很多研0的同学感觉本科阶段没学好&#xff0c;或者跨专业考研的同学&#xff0c;在知道了计量经济学的重要性之后&#xff0c;对于经济金融领域的“无计量、不科研…

Kind创建k8s - JAVA操作控制

kind 简介kind 架构安装 Kind (必备工具)docker官网kubectl官网kind官网校验安装结果 关于kind 命令 安装一个集群查看当前 Kubernetes 集群中的节点信息。查看当前命名空间下中的Pod&#xff08;容器实例&#xff09;的信息。使用 kind create cluster 安装&#xff0c;关于安…

智能优化算法应用:基于浣熊算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于浣熊算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于浣熊算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.浣熊算法4.实验参数设定5.算法结果6.参考文献7.MA…

中后缀表达式

一、利用后缀表达式进行计算 1&#xff09;解题思路 如果当前字符串是操作数&#xff0c;就将该操作数入栈&#xff1b;如果当前字符串是操作符&#xff0c;就取栈顶的两个操作数进行运算&#xff08;注意&#xff1a;第一个出栈的数为计算时的右操作数&#xff1b;第二个出栈…

继电器负载的使用方法有哪些?

继电器是通过电磁效应或电热效应实现电路的自动开关。继电器负载是指继电器所控制的负载&#xff0c;通常包括电机、灯泡、加热器等。正确使用继电器负载可以确保设备的正常运行和安全。以下是一些使用继电器负载的方法&#xff1a; 选择合适的继电器&#xff1a;根据负载的类型…

基于java+控件台+mysql的学生信息管理系统(含演示视频)

基于java控件台mysql的学生信息管理系统_含演示视频 一、系统介绍二、功能展示1.项目内容2.项目骨架3.数据库4.登录系统5.新增学生6.查询学生7.修改学生8.删除学生9.退出系统 四、其它1.其他系统实现五.获取源码 一、系统介绍 项目类型&#xff1a;Java SE项目&#xff08;控制…

大数据开发之Sqoop详细介绍

测试环境 CDH 6.3.1 Sqoop 1.4.7 一.Sqoop概述 Apache Sqoop&#xff08;SQL-to-Hadoop&#xff09;项目旨在协助RDBMS与Hadoop之间进行高效的大数据交流。用户可以在 Sqoop 的帮助下&#xff0c;轻松地把关系型数据库的数据导入到 Hadoop 与其相关的系统 (如HBase和Hive)中&…

Java经典框架之Spring MVC

Spring MVC Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring MVC 入门案例 2. 基…

Github 2023-12-23 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-23统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目6C项目2C项目1Jupyter Notebook项目1HTML项目1Go项目1非开发语言项目1 免费API集体清单 创建周期…

【中小型企业网络实战案例 二】配置网络互连互通

​【中小型企业网络实战案例 一】规划、需求和基本配置-CSDN博客 热门IT技术视频教程&#xff1a;https://xmws-it.blog.csdn.net/article/details/134398330?spm1001.2014.3001.5502 配置接入层交换机 1.以接入交换机ACC1为例&#xff0c;创建ACC1的业务VLAN 10和20。 <…

哪些超声波清洗机值得买?五款超声波清洗机实测大对比!

在当今快节奏的生活中&#xff0c;我们对于日常用品的清洁度要求越来越高。为了满足这一需求&#xff0c;超声波清洗机应运而生&#xff0c;以其高效、便捷的清洁方式赢得了广泛的市场。然而&#xff0c;面对市场上琳琅满目的超声波清洗机品牌和型号&#xff0c;很多时候都是无…

2047过滤空格(C语言)

目录 一&#xff1a;题目 二&#xff1a;思路分析 三&#xff1a;代码 一&#xff1a;题目 二&#xff1a;思路分析 1.首先&#xff0c;这道题是一个字符串的问题&#xff0c;我们要先知道字符串存放在char类型的数组中的&#xff0c;并不是一个变量就可直接存放的下一个完整…

iOS设备信息详解

文章目录 ID 体系iOS设备信息详解IDFA介绍特点IDFA新政前世今生获取方式 IDFV介绍获取方式 UUID介绍特点获取方式 UDID介绍获取方式 OpenUDID介绍 Bundle ID介绍分类其他 IP地址介绍获取方式 MAC地址介绍获取方式正常获取MAC地址获取对应Wi-Fi的MAC地址 系统版本获取方式 设备型…

使用 pytest.ini 文件控制输出 log 日志

一、前置说明 pytest.ini 文件中可以配置参数来控制 pytest 的运行行为,其存放路径要求与 conftest.py 一样。 项目根目录project_root/ ├── pytest.ini ├── tests/ │ └── test_demo.py以test开头的测试子目录project_root/ ├── tests/ │ ├── pytest.in…

Linux6.3、IO基础(文件描述符及分析系统接口细节)

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 前言 我们介绍文件描述符的顺序是&#xff1a; 为什么我们新打开几个文件&#xff0c;open返回值fd从3开始&#xff1f;fd与FILE*的关系&#xff1f;fd的理解&#xff1f; 我们就很疑惑&#xff0c;0,1,2哪里去了&#xff…