操作符重载——C/C++学习笔记

article/2025/11/11 15:38:29

此篇文章来自于网上,作为自己学习中的笔记,若有侵权行为,请告之,24小时之内必删除!下面就转入正题吧!

 

一、什么是操作符重载?
一看到重载,很容易就让人联想到成员函数重载,函数重载可以使名称相同的函数具有不同的实际功能,只要赋给这些同名函数不同的参数就可以了,操作符重载也是基于这一机制的。系统为我们提供了许多操作符,比如“+”,“[ ]”等,这些操作符都有一些默认的功能,而操作符重载机制允许我们给这些操作符赋予不同的功能,并能够按照普通操作符的使用格式来使用自己定义功能的操作符(即重载的操作符)。
定义之后,我们就可以按照平常使用操作符的格式来使用我们自己的重载操作符了。
操作符重载一般在类内部定义,就像成员函数一样定义,这叫做类成员重载操作符。当然也可以在类外定义,即非类成员操作符重载。
二、为什么要使用操作符重载?
举例说明,比如类String,该类有这样一个功能,可以将两个字符串连接成一个字符串,为此,我们可以给类String定义一个成员函数实现此功能,可以给该函数取一个形象的名字,比如concatenate或append,但是相比较,这两个名字都不如操作符“+=”形象直观。在这种情况下,我们就可以定义操作符“+=”的重载,来实现此功能。
也就是说,如果要定义一个函数,而这个函数的功能与操作符的功能比较类似时,这个时候我们就可以定义重载操作符,而不使用通常的成员函数定义。这里所说的操作符重载,指的是与系统定义的操作符重载,而不是说定义两个“+=”,这两个重载,这一点需要清楚。
但是这四个操作符不能用于重载::: *   ? :
三、如何声明操作符重载?
同普通函数类似,只不过它的名字包括关键字operator,以及紧随其后的一个预定义操作符。例如:
String& operator+=(const String&);
String& operator+=(const char*);
注意:上面的括号表示形式参数,即使操作符重载不需要参数,也应该写上一个空的“( )”,而不是将其省略,这一点其实和普通函数的声明是类似的。其实,声明的唯一区别就是名字不同而已。
四、怎样使用操作符重载?
两种操作符重载:类成员操作符重载和非类成员操作符重载。
1、类成员操作符重载
已知类String中声明了两个“==”操作符重载,分别是:
bool operator==(const char*) const;
bool operator==(const String&) const;
其中第一个重载的操作符允许我们比较一个String类对象是否等于一个C风格字符串,第二个允许我们比较两个String类对象是否相等。
示例代码:
#include<String.h>
int main()
{
       String flower;
       If(flower==”lily”) //正确:调用bool operator==(const char*) const;
       ……
       else
              if(“tulip”==flower) //错误
              …….
}
关键看一下,为什么第二个重载操作符的使用是错误的?
因为:只有在左操作数是该类类型的对象时,才会考虑使用作为类成员的重载操作符。
因为这里的”tulip”不是String类型对象,所以编译器试图找到一个内置操作符,它可以有一个C风格字符串的左操作数,然而事实上并不存在这样的操作符,所以编译时产生错误。
疑问:我们可以使用String类的构造函数将一个C风格字符串,转换成一个String对象,为什么编译器不能做以上转换呢?即
      if(String(“tulip”)==flower);//这样就是正确的
答:为了效率和正确性
重载操作符并不要求两个操作数的类型一定相同。可能有这样一个类Text,这个类的构造函数的参数及其成员重载操作符的参数都与String类一致,如果使编译器能够自动将C风格字符串转换成某个类型的对象,那么编译器首先会检索所有的类定义,选择能够提供正确构造函数和重载操作符的类进行转换,这无疑会增加程序的编译时间,还有就是类String和类Text均合适,编译器也不知道该将C风格字符串转换成String还是Text对象了。
 
对于类成员重载操作符,隐式的this指针被用作隐式的第一个参数,对于成员操作符,flower==”lily”会被编译器重写为:flower.operator==(“lily”);
 
2、非类成员操作符重载
为了解决上面的问题,我们可以考虑使用非类成员操作符代替类成员操作符,这样做的好处是左操作数不必非要是某个类的类型对象了,对于需要两个操作数的操作符重载,我们就可以定义两个参数了。比如:
bool operator==(const String&,const String&);
bool operator==(const String&,const char*);
可以看到,这两个全局重载操作符比成员操作符多了一个参数。
这样定义之后,还是上面的代码,当调用flower==”lily”时,会调用上面的bool operator==(const String&,const char*);。
然而“tulip”==flower会调用哪个操作符重载呢,我们并没有定义bool operator==(const char*,const String&);,我们是不是必须定义这样一个全局操作符重载呢?答案是否定的,因为当一个重载操作符是一个名字空间函数时,对于操作符的第一个和第二个参数,即等于操作符的左右两个操作数都会考虑转换,就像
int vi=1; double vd=2.0; vi=vi+vd; 会先将vd转换成int型,再做加法一样
这意味着,编译器将解释第二个用法如下:
bool operator==(String(“tulip”),flower)。这样会增加系统转换开销。
因此,如果需要频繁比较C风格字符串和String对象,那么最好定义上面的操作符重载,如果不频繁,我们只需定义下面一个就够了:
bool operator==(const String&,const String&);
 
分析:什么时候定义类成员操作符重载,什么时候定义非类成员操作符重载?
答:(1)如果一个重载操作符是类成员,那么只有当跟它一起使用的左操作数是该类对象时,它才会被调用,如果该操作符的左操作数必须是其他类型,那么重载操作符必须是非类成员操作符重载。
(2)C++要求,赋值(=),下标([ ]),调用(())和成员访问箭头(->)操作符必须被指定为类成员操作符,否则错误。
 
 
我们只能为类类型或枚举类型的操作数定义重载操作符,我们可以这样实现:把重载操作符声明为类的成员,或者声明为非类成员重载操作符但同时至少有一个类或者枚举类型的参数(按值传递或按引用传递)。这句话的意思,实际是说我们不能修改内置类型的操作符重载或添加操作符重载,比如下面的声明便是错误的:
int operator+(int,int);
这改变了内置类型int的+操作符的功能,所以错误。
 
操作符重载相关知识点:
五、友元(friend)
考虑到类成员操作符重载可以访问类中的私有变量,但是非类成员重载操作符却不能很方便的访问类的私有成员,为了方便起见,我们可以通过使用友元(friend)的方式,方便的访问类的私有成员。
举例:
class String
{
       friend bool operator==(const String&,const String&);
       friend bool operator==(const String&,const char*);
       public:
              //……..
       private:
              //………
}
注意:friend声明紧跟在类名之后,而不是放在public、private或protected中,因为友元不是授权类的成员,并且该关键字只能出现在类中。
经过上述声明之后,我们的非类成员重载操作符就可以直接方位String类的私有成员了。当然我们也可以不使用友元,而使通过该类的共有成员函数来间接访问该类的私有成员也是可以的,内联函数inline就不错,效率也不低。
 
由此看来,声明友元(friend)主要是为了方便高效的访问类的私有成员变量。
分析:什么时候应该使用友元:
(1)       某个类不提供公有的访问私有成员的函数。
(2)       使用共有成员函数访问私有成员变量效率比较差时。
 
友元除了用在非成员的重载操作符外,一个名字空间函数(比如全局函数),另一个在此之前定义的类的成员函数或者一个完整的类,均可以声明为某个类的成员。
如下声明:
class B;
class A
{
       friend class B;
       public:
              //…….
       Private:
              //……
}
通过上述声明,类A的成员函数可以访问所有的类B的私有成员,同样类B的成员函数可以访问所有类A的私有成员。
 
六、类类型对象的隐式类型转换
我们知道,系统提供的内置类型有隐式类型转换的功能,实际上我们也可以为自己编写的类提供隐式类型转换功能。这样,当我们在使用这种类的对象时,如果需要,编译器会自动调用该类的类型转换函数,实现类型转换功能。
C++提供了这样一种机制,通过它,每个类都可以定义一组“可被应用在该类型对象上的转换”
举例:
class SmallInt
{
       public:
              SmallInt(int ival):val(ival){};
              operator int(){return value;} ;//类型转换操作符SmallInt->int
       private:
              int value;
}
在上例中,操作符int()是一个转换函数,它定义了一个用户转换,实现在类类型和转换函数中指定的类型之间的转换,本例中,目标类型是int。
经过上面的定义后,SmallInt对象便可以用在任何可以使用int的地方,例如:
SmallInt si(3);
si+3.1415926;
这样,首先调用SmallInt转换函数,产生int型值3,然后将3变为3.0,和3.1415926相加。
实际上,上面类中定义转换函数还有一个好处就是:
省略了为该类定义重载操作符,尤其是重载操作符参数类型多样时。
1、  转换函数
格式:operator type( ); //参数必须为空,且( )不能省略,并且无返回值类型。
说明:type表示目标类型,它可以用内置类型,类类型或typedef名取代,但不允许表示数组,转换函数必须是类的成员函数,并且不能指定返回类型和参数表。
 
显式的强制类型转换会导致调用转换函数,如果被转换值的类型是一个类类型,它有一个转换函数,并且该转换函数的类型是强制转换所指定的类型,则调用这个类的强制转换函数。
比如:
char* tokName=static_cast<char*>(tok);//tok表示对象,它所属的类提供一个到char*的转换函数。
2、  用构造函数作为转换函数
在一个类的构造函数中,凡是只带有一个参数的构造函数,例如SmallInt的构造函数SmallInt(int),都定义了一组隐式转换,把构造函数的参数类型转换成该类类型。
注意:是将int转换成SmallInt型。和前面说的转换函数功能正好相反。
举例:
void calc(SmallInt);
int  vi;
calc(vi);
这时,编译器就会隐式调用类SmallInt的构造函数SmllInt(int),将vi转换成SmallInt对象,然后再将这个对象传递给函数calc( )。
可以这样理解:
{
       SmallInt temp=SmallInt(i);
       Calc(temp);
}
这个大括号指出temp这个临时对象的生命周期。
 
注意:编译器不会使用一个显式构造函数(关键字explicit标志)来执行隐式类型转换,但是却可以使用这样的构造函数来进行强制转换(即static_cast<>)。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/btooth/archive/2006/07/26/981245.aspx



http://chatgpt.dhexx.cn/article/2yfCCoqc.shtml

相关文章

什么是操作符重载

一、什么是操作符重载 操作符重载可以分为两部分&#xff1a;“操作符”和“重载”。说到重载想必都不陌生了吧&#xff0c;这是一种编译时多态&#xff0c;重载实际上可以分为函数重载和操作符重载。运算符重载和函数重载的不同之处在于操作符重载重载的一定是操作符。我们不妨…

前端知识点总结 Vue JS CSS

前端知识点 MVVM和MVC的区别什么是Vue生命周期钩子函数触发顺序 VueVue优点父子通信&#xff0c;兄弟通信指令V-if和V-show区别 Vue-loaderVue-key的作用v-modalVue data必须是函数的问题Vue slot Vue-router多个router-viewroute与router的区别导航守卫懒加载 ES6JavaScript同…

JavaScript进阶之手写Promise

前言 Promise异步编程的一种解决方案&#xff0c;比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现&#xff0c;ES6 将其写进了语言标准&#xff0c;统一了用法&#xff0c;原生提供了Promise对象。这里手写一次&#xff0c;希望能和大家一起彻底…

【数据库】MongoDB数据库详解

目录 一&#xff0c;数据库管理系统 1&#xff0c; 什么是数据库 2&#xff0c;什么是数据库管理系统 二&#xff0c; NoSQL 是什么 1&#xff0c;NoSQL 简介 2&#xff0c;NoSQL数据库 3&#xff0c;NoSQL 与 RDBMS 对比 三&#xff0c;MongoDB简介 1&#xff0c; MongoDB 是什…

面试06,[长亮科技]()(offer)、[荔枝]()FM(在确定部门和薪资)、[涂鸦智能]()(第一轮电话面半小时,待后续)、华资软件(HR面)、[广州速游]()(已挂)。至于公司怎么样不加以言论。

作者&#xff1a;Carson-Zhao 链接&#xff1a;https://ac.nowcoder.com/discuss/522002?type2&order0&pos16&page1&ncTraceId&channel-1&source_iddiscuss_tag_nctrack 来源&#xff1a;牛客网 总结一下这几天的面试吧&#xff01;从19号到现在23号…

SQL Foundation(1--13)

1&#xff1a;关系数据库的由来&#xff1a; IBM的工程师Dr E F codd 的关系型数据库模型发表于1970 论文名称&#xff1a; A relational Model of data for Large Shared Data Bank (这个在wiki 和google上可以搜到) SQL: Structured query language&#xff1a; oracle官方…

一、快速入门 MongoDB 数据库

文章目录 一、NoSQL 是什么1.1 NoSQL 简史1.2 NoSQL 的种类及其特性1.3 NoSQL 特点1.4 NoSQL 的优缺点1.5 NoSQL 与 SQL 数据库的比较 二、MongoDB 基础知识2.1 MongoDB 是什么2.2 MongoDB 的体系结构2.3 MongoDB 的特点2.4 MongoDB 键特性2.5 MongoDB 的核心服务和工具2.6 Mon…

数据库总结(考研复试和期末复习皆可用)

数据库总结 点击下载该文档 密码&#xff1a;cqoq 本人自制了简答题的速记卡片 地址&#xff0c;大家可以参考使用。[下载Markji App 使用] 第一章 绪论 1.1 数据库系统概述 数据库管理系统(DBMS)的功能: 数据定义功能数据组织、存储和管理数据库操纵功能数据库的事务和运行…

一步步教你轻松学KNN模型算法

一步步教你轻松学KNN模型算法 ( 白宁超 2018年7月24日08:52:16 ) 导读&#xff1a;机器学习算法中KNN属于比较简单的典型算法&#xff0c;既可以做聚类又可以做分类使用。本文通过一个模拟的实际案例进行讲解。整个流程包括&#xff1a;采集数据、数据格式化处理、数据分析、数…

Oracle实战详解

Oracle实战详解 1.oracle介绍 ORACLE数据库系统是美国ORACLE公司&#xff08;甲骨文&#xff09;提供的以分布式数据库为核心的一组软件产品&#xff0c;是目前最流行的客户/服务器(CLIENT/SERVER)或B/S体系结构的数据库之一。比如SilverStream就是基于数据库的一种中间件。ORA…

数据库|SQL / MySQL的基本理论用法

本文从数据库MySQL的数据类型、关系模型、增删改查语句、管理MySQL、实用SQL语句、事务等方面进行介绍。 数据类型 对于一个关系表&#xff0c;除了定义每一列的名称外&#xff0c;还需要定义每一列的数据类型。关系数据库支持的标准数据类型包括数值、字符串、时间等&#xf…

KNN模型算法研究与案例分析

KNN模型算法研究与案例分析( 白宁超 2018年8月29日15:39:13 ) 导读&#xff1a;机器学习算法中KNN属于比较简单的典型算法&#xff0c;既可以做聚类又可以做分类使用。本文通过一个模拟的实际案例进行讲解。整个流程包括&#xff1a;采集数据、数据格式化处理、数据分析、数据归…

SQL总结

目录 简介 在Android中存储数据有时会用到数据库&#xff0c;Android给我们提供了 一系列的API来操作数据库&#xff0c;非常简单&#xff0c;我们只需要输入对应的SQL语句&#xff0c;甚至不懂SQL语句&#xff0c;只传入对应的参数即可使用。还有一些第三方库&#xff0c;如G…

Windows开机启动项设置详解

一、开机启动原理 Windows系统都有一个“启动”文件夹&#xff0c;把需要打开的程序的快捷方式或脚本放到“启动”文件夹里&#xff0c;就可以实现开机自启动。 启动”文件夹分为两种&#xff1a;“系统启动文件夹”和“用户启动文件夹”。 系统启动文件夹 Win10系统“启动”…

「C#」设置开机启动

自己写了个监控键盘按键的小程序。 在界面上实时显示按下的键&#xff0c;但是想实现程序的开机自启如何实现呢。 开机自启动一种是在windows的“C:\Users\用户名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup”家快捷方式。但是这种方法自测有时候不成功。…

centos7 设置开机启动项

高端的废话就是没有引言这种废话。 1.这里我已我的centos7为例输入&#xff1a; systemctl list-unit-files #查看开机启动表如图下&#xff1a; 最左边就是服务 &#xff0c;最右边就是状态 。如当你想要服务器开机启动firewalld&#xff08;防火墙&#xff09;输入 system…

计算机怎么管理自启,电脑如何设置开机启动项

大家都知道将程序添加到开机启动项进入系统就可以自动打开了&#xff0c;但是有些流氓软件会强制进入开机启动项&#xff0c;这就导致电脑开机速度变慢&#xff0c;内存占用过多&#xff0c;运行卡顿的问题。下面&#xff0c;我就教大家如何设置开机启动 现在几乎家家户户都配备…

电脑设置开机

我们知道电脑可以通过修改系统任务计划来实现定时关机的功能&#xff0c;那么&#xff0c;能不能让电脑实现自动开机的功能呢?答案是可以的&#xff0c;我们可以通过BIOS设置&#xff0c;指定电脑在某个时间点自动开机&#xff0c;接下来&#xff0c;小编来介绍一下如何通过BI…

nginx 设置开机自启动

一、下载 在windows下实现开机自启动需要一个开源项目Windows Service Wrapper 来实现。 我用的是这个版本。 下载下来&#xff0c;放在Nginx根目录下 下载下来&#xff0c;放在Nginx根目录下&#xff0c;名字改为start-nginx.exe&#xff0c;再新建一个txt文件&#xff0c…

Win11开机启动项怎么调整,Win11开机启动项怎么设置

Win11开机启动项怎么调整&#xff1f;Win11开机启动项怎么设置&#xff1f;现在很多应用或软件下载安装之后默认都是开机自启的&#xff0c;如果开机自启的软件多了的话难免会导致系统开机速度变慢。最近有使用win11系统的小伙伴就遇到了这个问题&#xff0c;有网友想了解怎么设…