C++核心编程——运算符重载

C++核心编程——运算符重载

  • 运算符重载的方法
  • 运算符重载函数作成员函数与友元函数
  • 重载双目运算符
  • 重载单目运算符
  • 重载流插入运算符和"<<"和流提取运算符">>"
    • 重载流插入运算符和"<<"
    • 流提取运算符">>"

运算符重载的方法

运算符重载的方法是定义一个重载运算符的函数,使指定运算符不能能实现原有的功能,还能实现在函数中指定新的功能。运算符重载的实质是函数的重载。
重载运算符的函数一般格式如下:
函数类型 operator 运算符名称(形参表)
{ 对运算符的重载处理 }

在这里插入图片描述
典例:对运算符 “+” 实现重载,使之能用于两个复数相加。

#include <iostream>
using namespace std;
class Complex{
public:Complex(){real=0;imag=0;}//自定义有参构造 无参构造不再提供,若要用,需要自定义 Complex(int, int);Complex operator+(Complex &c);void display();private:int real;int imag;
};Complex::Complex(int real, int imag)
{this->real = real;this->imag = imag;
}Complex Complex::operator+(Complex &c)
{Complex tempc;tempc.real = real + c.real;tempc.imag = imag + c.imag;return tempc;
}
void Complex::display()
{cout << "(" << real << "," << imag << "i)" << endl;
}
int main()
{Complex c1(3,4);Complex c2(5,-10);Complex c3;c3 = c1 + c2; 	//相当于:c3 = c1.operator+(c2); cout << "c1=";		c1.display();cout << "c2=";		c2.display();cout << "c1+c2=";	c3.display();return 0;
} 

说明:

  • 自定义有参构造函数,则无参构造不再提供,若要用,需要重新自定义
  • 程序 c3 = c1 + c2 相当于 c3 = c1.operator+(c2); ,使用运算符重载能使用户程序易于编写,阅读和维护。

运算符重载函数作成员函数与友元函数

在这里插入图片描述
如果将运算符重载函数作为成员函数,它可以通过this指针自由地访问本类的数据成员,因此可以少写一个函数的参数。必须要求运算表达式(如c1+c2)中第1个参数即运算符左侧的操作数)是一个类对象而且与运算符函数的类型相同。因为必须通过类的对象去调用该类的成员函数,而且只有运算符重载函数返回值与该对象同类型,运算结果才有意义。

  • 如果想要计算复数+整数,如c1+i,需要重新重载运算符
    Complex Complex::operator+(int i)
    {Complex tempc;tempc.real = real + i;tempc.imag = imag;return tempc;
    }
    
  • 如果想要计算整数+复数,如i+c1, 则第一个参数不是类对象,必须使用友元函数重载运算符。
    Complex operator+(int i, Complex &c)
    {Complex tempc;tempc.real = i + c.real;tempc.imag = c.imag;return tempc;
    }
    
  • 一般将双目运算符重载为友元函数
    Complex operator+(Complex &c1, Complex &c2)
    {Complex tempc;tempc.real = c1.real + c2.real;tempc.imag = c1.imag + c2.imag;return tempc;
    }
    

从原则上讲,要尽量将重载运算符函数作为成员函数,但还因考虑其他各方因素和习惯,以下方式可供参考
(1)C++规定,赋值运算符“=”、下标运算符“[]”、函数调用运算符“()”、成员运算符“->”、必须作为成员函数重载。
(2)流插人“<<”和流提取运算符“>>”类型转换运算符函数不能定义为类的成员函数,只能作为友元函数。
(3)一般将单目运算符和复合运算符( +=,-=,/=,*=,&=,!=,^=,%=,>>=,<<=)重载为成员函数。
(4)一般将双目运算符重载为友元函数

完整代码(可供参考)

#include <iostream>
using namespace std;
class Complex{
public:Complex(){real=0;imag=0;}Complex(int, int);Complex::operator+(int i);friend operator+(int i, Complex &c);friend Complex operator+(Complex &c1, Complex &c2);void display();private:int real;int imag;
};//构造函数 
Complex::Complex(int real, int imag)
{this->real = real;this->imag = imag;
}//复数+整数 
Complex Complex::operator+(int i)
{Complex tempc;tempc.real = real + i;tempc.imag = imag;return tempc;
}//整数 +复数 
Complex operator+(int i, Complex &c)
{Complex tempc;tempc.real = i + c.real;tempc.imag = c.imag;return tempc;
}
//复数+复数 一般情况下双目运算符重载为友元函数 
Complex operator+(Complex &c1, Complex &c2)
{Complex tempc;tempc.real = c1.real + c2.real;tempc.imag = c1.imag + c2.imag;return tempc;
}void Complex::display()
{cout << "(" << real << "," << imag << "i)" << endl;
}int main()
{Complex c1(3,4);Complex c2(5,-10);Complex c3,c4,c5;c3 = c1 + c2; 	//相当于:c3 = c1.operator+(c2); c4 = c1 + 4;c5 = 5 + c2;cout << "c1=";		c1.display();cout << "c2=";		c2.display();cout << "c1+c2=";	c3.display();cout << "c1+4=";	c4.display();cout << "5+c2=";	c5.display();return 0;
} 

重载双目运算符

双目运算符是C++中最常见的运算符,双目运算符有两个操作数,通常在运算符的左右侧,重载函数应该有两个参数,也通常设置为友元函数作为运算符重载函数。
典例:声明一个字符串类String,用来存放不定长的字符串,重载运算符“==”和“>”,用于两个字符串的等于、小于和大于的比较运算。
为了程序的设计了与便于理解,程序设计分步骤编写。
1. 先建立一个String类

#include <iostream>
#include <string.h>using namespace std;
class String{
public://构造及打印函数 String(){p=NULL;}		//无参构造 String(char *str){p=str;}	//有参构造 void display(){cout << p << endl;}	//打印字符串 	
private:char *p;
};int main()
{//测试代码 String str1("Hello"),str2("world");str1.display();str2.display();return 0;
} 

2. 重载运算符>
通过全局函数作类友元的方式重载运算符>,其重载函数实现体如下所示。

bool operator>(String &str1, String &str2)
{if(strcmp(str1.p,str2.p)>0)return true;elsereturn false; 
}

这只是一个并不很完善的程序,但是,已经完成实质性的工作了,运算符重载成功了。既然对运算符“>”的重载成功了,其他两个运算符的重载如法炮制即可
3. 重载其他运算符

  • 重载运算符“<”

    重载运算符< 
    bool operator<(String &str1, String &str2)
    {if(strcmp(str1.p,str2.p)<0)return true;elsereturn false; 
    }
    
  • 重载运算符“==”

    //重载运算符= 
    bool operator==(String &str1, String &str2)
    {if(strcmp(str1.p,str2.p)==0)return true;elsereturn false; 
    }
    
  • 同时记得将上述三个重载函数声明为类的友元函数

    //运算符重载函数 
    friend bool operator>(String &str1, String &str2);
    friend bool operator<(String &str1, String &str2);	
    friend bool operator==(String &str1, String &str2);	
    
  • 测试代码:

    int main()
    {//测试代码 String str1("Hello"),str2("world");cout << (str1>str2) << endl; cout << (str1<str2) << endl; cout << (str1==str2) << endl; return 0;
    } 
    
  • 测试结果

    0
    1
    0

4. 修饰完善,优化输出

//封装比较函数 优化输出
void compare(String &str1, String &str2)
{if((str1 > str2)==1){str1.display();	cout << " > ";	str2.display();}else if ((str1 < str2)==1){str1.display(); cout << " < ";	str2.display(); }	else{str1.display(); cout << " = ";	str2.display();}	
}

增加了一个compare函数用来对两个字符串进行比较,并输出相应的信息。这样可以减轻主函数的负担,同时使主函数简明易读。
先搭框架、逐步扩充、由简到繁、最后完善。边编程、边调试、边扩充。
完整参考程序:

#include <iostream>
#include <string.h>using namespace std;
class String{
public://构造及打印函数 String(){p=NULL;}			//无参构造 String(char *str){p=str;}	//有参构造 void display(){cout << p;}	//打印字符串//运算符重载函数 friend bool operator>(String &str1, String &str2);friend bool operator<(String &str1, String &str2);	friend bool operator==(String &str1, String &str2);	private:char *p;
};void compare(String &str1, String &str2)
{if((str1 > str2)==1){str1.display();	cout << " > ";	str2.display();}else if ((str1 < str2)==1){str1.display(); cout << " < ";	str2.display(); }	else{str1.display(); cout << " = ";	str2.display();}	
}int main()
{//测试代码 String str1("hello"),str2("world");compare(str1,str2);return 0;
} //重载运算符> 
bool operator>(String &str1, String &str2)
{if(strcmp(str1.p,str2.p)>0)return true;elsereturn false; 
}重载运算符< 
bool operator<(String &str1, String &str2)
{if(strcmp(str1.p,str2.p)<0)return true;elsereturn false; 
}//重载运算符= 
bool operator==(String &str1, String &str2)
{if(strcmp(str1.p,str2.p)==0)return true;elsereturn false; 
}

重载单目运算符

重载单目运算符与重载双目运算符相似,但由于单目运算符只有一个操作数,因此单目运算符重载函数只有一个参数,如果运算符重载函数作为成员函数,则还可省略此参数。

典例:以自增运算符++为例,设计一个Time类,含数据成员minute(分)和sec(秒),模拟秒表,每次走1秒,满60秒进1分钟,此时秒又从0起算。要求输出分和秒的值。

#include <iostream>
#include <string.h>using namespace std;
class Time{
public://构造及打印函数 Time(){min=0;sec=0;}Time(int,int);void display();//运算符重载Time operator++();private:int min;int sec;
};//构造函数 
Time::Time(int min, int sec)
{this->min = min;this->sec = sec;
}
//运算符重载 
Time Time::operator++()
{sec++;if(sec>=60){min++;sec=0;}return *this;	
}
//打印时间	
void Time::display()
{cout << min << ":" << sec << endl;
}int main()
{int i;Time time1(34,12);for(i=0;i<61;i++){++time1;time1.display();}return 0;
} 

程序对运算符“++”进行了重载,使它能用于Time类对象。
但问题是:“++”和“–”运算符有两种使用方式,前置自增运算符和后置自增运算符,它们的作用是不一样的,在重载时怎样区别这二者呢?
针对“++”和“–”这一特点,C++约定:在自增(自减)运算符重载函数中增加一个int型形参就是后置自增(自减)运算符函数。
在上述程序的基础上增加对后置自增运算符的重载。

  • ++运算符重载后置 重载函数
    //运算符重载 ++ 后置 
    Time Time::operator++(int)
    {//建立临时对象 temp 并读取当前值 Time temp(*this);	sec++;if(sec>=60){min++;sec=0;}return temp;	
    }
    
  • 主函数程序程序
    int main()
    {int i;Time time1(34,12);Time time2;time2=time1++;cout << "time2=tim1++: time1=";	time1.display();	cout << "  time2=";	time2.display();return 0;
    } 
    

重载后置自增运算符时,多了一个int型的参数,增加这个参数只是为了与前置自增运算符重载函数有所区别,此外没有任何作用。在定义函数时也不必使用此参数因此可省写参数名,只须在括号中写int 即可。

重载流插入运算符和"<<“和流提取运算符”>>"

如果想用输出和输入自已声明的类型的数据,必须对它们重载
对"<<“和”>>"重载的函数形式如下:
ostream & operator<<(ostream &, 自定义类 &)
istream & operator>>(istream &, 自定义类 &)
重载“>>”和“<<”的函数只能作为友元函数,不能将他们定义为成员函数

重载流插入运算符和"<<"

典例:在上述代码的基础上,重载输出运算符“<<”输出复数

#include <iostream>
#include <string.h>using namespace std;
class Complex{
public://构造及打印函数 Complex(){real=0;imag=0;}					//无参构造 Complex(double i,double j){real=i;imag=j;}	//有参构造 Complex operator+(Complex &);				//+号运算符重载 friend ostream &operator<<(ostream &output, Complex &c);	//重载coutprivate:double real;double imag;
};Complex Complex::operator+(Complex &c)
{Complex temp;temp.real = real + c.real;temp.imag = imag + c.imag;return temp;
} ostream &operator<<(ostream &output, Complex &c)
{output << "(" << c.real << "," << c.imag << "i)";return output;
}int main()
{//测试代码 Complex c1(1.2, 2.3);Complex c2(0.8, 2.7);Complex c3;c3 = c1 + c2;cout << c1 << "+" << c2 << "=" << c3;return 0;
}

程序中重载了运算符“<<”运算符重载函数“operator<<”中的形参output是ostream类对象的引用,形参名output是用户任意起的。
  运算符“<<”的左面是cout,前面已提到cout是在头文件iostream中声明的ostream类对象。“<<”的右面是c3,它是Complex类对象。由于已将运算符“<<”的重载函数声明为Complex类的友元函数编译系统把cout<<c3解释为:
  operator<<(cout, c1)
即以cout和c1作为实参调用下面的“operator<<”函数:

ostream &operator<<(ostream &output, Complex &c)
{output << "(" << c.real << "+" << c.imag << "i)";return output;
}

调用函数时,形参output成为实参cout的引用,形参c成为c1的引用。因此调用函数的过程相当于执行

cout<< "(" << c1.real << "," << c1.imag << "i)";

return output的作用:
  连续向输出流插入信息,output是ostream类的对象的引用,因此return output就是return cout.

流提取运算符">>"

  • >>运算符重载函数
    istream &operator>>(istream &input, Complex &c) 
    {input >> c.real >> c.imag;return input;
    }
    
    函数的返回值仍然为输入流的引用,第一个参数为输入流的引用,第二个参数为复数的引用,当调用以下函数时,第一个参数被赋值为cin的引用,第二个参数被赋值为c1的引用,程序就相当于执行cin >> c1.real >> c1.imag,执行完毕后返回istream的引用,使得能够继续连续输入c2.
  • 函数的调用
    cin >> c1 >> c2;	//其中c1,c2代表2个复数
    

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

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

相关文章

finebi 新手入门案例

finebi 新手入门案例 连锁超市销售数据分析 步骤&#xff1a; 准备公共数据新建分析主题处理数据在数据中分析在图形中分析数据大屏 准备公共数据 点击公共数据 点击新建文件夹 修改文件夹名称 上传数据 鼠标悬停在文件夹上&#xff0c;右侧出现 鼠标悬停在文件夹上&#x…

Ubuntu中MySQL安装与使用

一、安装教程&#xff1a;移步 二、通过sql文件创建表格&#xff1a; 首先进入mysql&#xff1a; mysql -u 用户 -p 回车 然后输入密码source sql文件&#xff08;路径&#xff09;;上面是sql语句哈&#xff0c;所以记得加分号。 sql文件部分截图&#xff1a; 创建成功后的部…

《opencv实用探索·七》一文看懂图像卷积运算

1、图像卷积使用场景 图像卷积是图像处理中的一种常用的算法&#xff0c;它是一种基本的滤波技术&#xff0c;通过卷积核&#xff08;也称为滤波器&#xff09;对图像进行操作&#xff0c;使用场景如下&#xff1a; 模糊&#xff08;Blur&#xff09;&#xff1a; 使用加权平…

与原有视频会议系统对接

要实现与原有视频会议系统对接&#xff0c;需要确保通信协议的一致性。连通宝视频会议系统可与第三方视频会议系统对接。实现与第三方会议系统对接还可以使用会议室连接器&#xff0c;可以确保不同系统之间的数据传输和交互。 具体对接流程可能因不同品牌和类型的视频会议系统而…

蓝桥杯第四场双周赛(1~6)

1、水题 2、模拟题&#xff0c;写个函数即可 #define pb push_back #define x first #define y second #define int long long #define endl \n const LL maxn 4e057; const LL N 5e0510; const LL mod 1e097; const int inf 0x3f3f; const LL llinf 5e18;typedef pair…

BEV+Transformer架构加速“上车”,智能驾驶市场变革开启

BEVTransformer成为了高阶智能驾驶领域最为火热的技术趋势。 近日&#xff0c;在2023年广州车展期间&#xff0c;不少车企及智能驾驶厂商都发布了BEVTransformer方案。其中&#xff0c;极越01已经实现了“BEVTransformer”的“纯视觉”方案的量产&#xff0c;成为国内唯一量产…

Leetcode-二叉树oj题

1.二叉树的前序遍历 144. 二叉树的前序遍历https://leetcode.cn/problems/binary-tree-preorder-traversal/这个题目在遍历的基础上还要求返回数组&#xff0c;数组里面按前序存放二叉树节点的值。 既然要返回数组&#xff0c;就必然要malloc一块空间&#xff0c;那么我们需…

C# WPF上位机开发(第一个应用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 万事开头难&#xff0c;很多事情都是难在第一步。走出了这第一步&#xff0c;回过头看以前走的每一步&#xff0c;发现其实也不难。用c# wpf编写界…

系列九、声明式事务(xml方式)

一、概述 声明式事务(declarative transaction management)是Spring提供的对程序事务管理的一种方式&#xff0c;Spring的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明&#xff0c;是指在配置文件中声明&#xff0c;用在Spring配置文件中声明式的处理事务来…

Go 数字类型

一、数字类型 1、Golang 数据类型介绍 Go 语言中数据类型分为&#xff1a;基本数据类型和复合数据类型基本数据类型有&#xff1a; 整型、浮点型、布尔型、字符串复合数据类型有&#xff1a; 数组、切片、结构体、函数、map、通道&#xff08;channel&#xff09;、接口 2、…

excel合并单元格教程

在表格里&#xff0c;总是会遇到一级表格、二级表格的区别&#xff0c;这时候一级表格会需要合并成一个大格子&#xff0c;那么excel如何合并单元格呢&#xff0c;其实使用快捷键或者功能键就可以了。 excel如何合并单元格&#xff1a; 1、首先我们用鼠标选中所有要合并的单元…

计算机网络之数据链路层

目录 一、数据链路层的几个共用问题 1.1数据链路和帧 1.2三个基本问题 二、点对点协议PPP 2.1PPP协议的特点 2.2PPP协议的帧格式 2.3 PPP协议的工作状态 三、使用广播信道的数据链路层 3.1局域网的数据链路层 数据链路层的两个子层 3.2CSMA/CD协议 3.3使用集线器的…

云服务器anaconda(py39)+pytorch1.12.0(cu113)

用xshell连接ip地址&#xff0c;端口号22&#xff0c;输入用户密码 查看当前版本 conda -V conda info --envs 如果不是需要的版本&#xff0c;使用 anaconda-clean --yes rm -rf anaconda3 删除文件夹 安装anaconda 2022 10 py3.9 wget https://repo.anaconda.com/archi…

干货:如何拯救程序员的苦恼?

本站的同志大多都是IT行业的从业者。今天博主给大家推荐几个帮助程序员解决烦恼的网站&#xff0c;大家一定要收藏哦&#xff01; 目录 1. 图标平台——ByteDance IconPark 2. 进制转换——so json在线工具 3. 代码高亮——CodeInWord 4. 取名利器——codelf 5. 颜色图签—…

外包搞了3年,感觉技术退步很明显......

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…

uniapp上架app store详细攻略

目录 uniapp上架app store详细攻略 前言 一、登录苹果开发者网站 二、创建好APP 前言 uniapp开发多端应用&#xff0c;打包ios应用后&#xff0c;会生成一个ipa后缀的文件。这个文件无法直接安装在iphone上&#xff0c;需要将这个ipa文件上架app store后&#xff0c;才能通…

R语言实操记录——R包无法安装,报错:Warning in system(cmd) : ‘make‘ not found

R语言 R语言实操记录——R包无法安装&#xff0c;报错&#xff1a;Warning in system(cmd) : ‘make‘ not found 文章目录 R语言一、起因二、具体步骤2.1、确认问题源2.2、安装RTools2.3、与R(/Rstudio)绑定2.4、验证可行性 三、疑惑 一、起因 R语言在包的安装上是真的方便&…

Visual Studio通过ClaudiaIDE插件设置背景图片

首先&#xff0c;在VS菜单栏上选择扩展-管理扩展&#xff0c;搜索插件为 ClaudiaIDE&#xff0c; 下载完成之后&#xff0c;关闭VS&#xff0c;点击Modify按钮安装&#xff1a; 等待安装完成&#xff0c;进入 VS , 打开 工具----选项---- ClauDiaIDE 界面 这个是背景色调 我选的…

反欺诈指南:东南亚数字经济反欺诈注意事项

目录 东南亚各类网络欺诈肆虐 科技助力东南亚反欺诈 东南亚做反欺诈需要注意四个方面 据谷歌、淡马锡和贝恩公司发布的一份报告显示&#xff0c;尽管东南亚地区的经济增长有所放缓&#xff0c;但2023年数字经济仍预计创造约100亿美元的收入&#xff0c;数字支付占该地区总交易额…

OpenCV简介及安装

前言 因为最近想做图像处理、人脸检测/识别之类的相关开发&#xff0c;所以就开始补OpenCV的相关知识&#xff0c;便开个专栏用于记录学习历程和在学习过程中遇到的一些值得注意的重点和坑。 学习过程基本上也是面向官方文档和Google。 简介 OpenCV(开源的计算机视觉库)是基于…