首页
技术博客
PHP教程
数据库技术
前端开发
HTML5
Nginx
php论坛
新用户注册
|
会员登录
PHP教程
技术博客
编程问答
PNG素材
编程语言
前端技术
Android
PHP教程
HTML5教程
数据库
Linux技术
Nginx技术
PHP安全
WebSerer
职场攻略
JavaScript
开放平台
业界资讯
大话程序猿
登录
极速注册
取消
热门标签 | HotTags
node.js
string
regex
loops
php5
future
replace
byte
bash
perl
cPlusPlus
datetime
c语言
less
fetch
python2
request
frameworks
golang
include
express
search
header
buffer
flutter
web3
foreach
const
shell
main
jsp
subset
chat
bytecode
php8
instance
数组
triggers
select
expression
ascii
tree
callback
format
nodejs
utf-8
import
stream
hash
eval
plugins
erlang
tags
hashtable
bit
js
range
blob
jar
timezone
filter
lua
scala
metadata
php
copy
sum
actionscrip
rsa
vbscript
hashset
cmd
default
web
netty
dagger
process
httpclient
require
当前位置:
开发笔记
>
编程语言
> 正文
操作符重载浅析
作者:涛之圣首到 | 来源:互联网 | 2024-10-08 17:16
什么是操作符重载?一看到重载,很容易就让人联想到成员函数重载,函数重载可以使名称相同的函数具有不同的实际功能,只要赋给这些同名函数不同的参数就可以了,操作符重载也是基于这一机制的。系统为我们提供了许多
什么是操作符重载?
一看到重载,很容易就让人联想到成员函数重载,函数重载可以使名称相同的函数具有不同的实际功能,只要赋给这些同名函数不同的参数就可以了,操作符重载也是基于这一机制的。系统为我们提供了许多操作符,比如“+”,“[ ]”等,这些操作符都有一些默认的功能,而操作符重载机制允许我们给这些操作符赋予
不同的功能,
并能够按照普通操作符的使用格式来使用自己定义功能的操作符(即重载的操作符)
。
定义之后,我们就可以
按照平常使用操作符的格式来使用我们自己的重载操作符了。
操作符重载一般在
类内部定义,就像成员函数一样定义,这叫做类成员重载操作符。当然也可以在
类外定义
,即非类成员操作符重载。
二、为什么要使用操作符重载?
举例说明,比如类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
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; 会先将vi转换成double型,再做加法一样
这意味着,编译器将解释第二个用法如下:
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
(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<>)。
string
const
char
include
int
main
ip
编译
text
写下你的评论吧 !
吐个槽吧,看都看了
会员登录
|
用户注册
推荐阅读
main
使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ...
[详细]
蜡笔小新 2024-12-27 16:07:12
main
使用Objective-C和dispatch库实现并发素数计算
本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ...
[详细]
蜡笔小新 2024-12-28 08:44:35
main
UNP 第9章:主机名与地址转换
本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ...
[详细]
蜡笔小新 2024-12-27 11:26:39
main
Weight the Tree(树形dp)
题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!----- ...
[详细]
蜡笔小新 2024-12-26 15:55:56
main
C++ 中的数组与动态数组初始化
本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ...
[详细]
蜡笔小新 2024-12-26 15:38:03
main
java编写的简易计算器
主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ...
[详细]
蜡笔小新 2024-12-27 18:18:10
main
USACO 2014 Jan - Moolympics区间记录优化算法
题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ...
[详细]
蜡笔小新 2024-12-27 18:14:31
const
分页插件3指定到某一页
前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ...
[详细]
蜡笔小新 2024-12-27 15:19:01
main
组合数学问题:棋盘上的组合数计算
本文探讨了如何在模运算下高效计算组合数C(n, m),并详细介绍了乘法逆元的应用。通过扩展欧几里得算法求解乘法逆元,从而实现除法取余的计算。 ...
[详细]
蜡笔小新 2024-12-26 21:41:44
main
扫描线三巨头 hdu1928hdu 1255 hdu 1542 [POJ 1151]
学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ...
[详细]
蜡笔小新 2024-12-26 20:04:36
main
新浪笔试题
1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ...
[详细]
蜡笔小新 2024-12-27 19:32:17
bash
CentOS7源码编译安装MySQL5.6
2019独角兽企业重金招聘Python工程师标准一、先在cmake官网下个最新的cmake源码包cmake官网:https:www.cmake.org如此时最新 ...
[详细]
蜡笔小新 2024-12-27 17:49:56
bash
深入理解 SQL 视图、存储过程与事务
本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ...
[详细]
蜡笔小新 2024-12-27 17:40:42
replace
Java面试题解析
本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ...
[详细]
蜡笔小新 2024-12-27 13:55:14
main
C#中获取进程主窗口句柄的实现方法
本文介绍了如何在C#中启动一个应用程序,并通过枚举窗口来获取其主窗口句柄。当使用Process类启动程序时,我们通常只能获得进程的句柄,而主窗口句柄可能为0。因此,我们需要使用API函数和回调机制来准确获取主窗口句柄。 ...
[详细]
蜡笔小新 2024-12-27 03:39:09
涛之圣首到
这个家伙很懒,什么也没留下!
Tags | 热门标签
node.js
string
regex
loops
php5
future
replace
byte
bash
perl
cPlusPlus
datetime
c语言
less
fetch
python2
request
frameworks
golang
include
express
search
header
buffer
flutter
web3
foreach
const
shell
main
RankList | 热门文章
1
手机里的私密照片被别人看到了怎么办?:图片设置私密
2
美柚号被封了,怎么解封?
3
抖音定位怎么设置
4
word目录页码点点点怎么弄_word目录上的点点点教程
5
怎么固定电脑打开的窗口大小?
6
美团外卖如何绑定打印机 美团打印机绑定教程
7
Win10专业版|工作站版|教育版|企业版版本转换升级教程+产品密钥win10教育版升级企业版
8
电动自行车新国标正式发布,推动电池产业转型升级
9
揭秘秦淮八艳的陈圆圆与复社四公子的冒辟疆之间的爱情故事
10
安卓手机投屏电视怎么设置?投屏其实很简单
11
jmeter 线程组、元件的作用域与执行顺序、聚合报告 详解(2)
12
【涨知识】网友们自行整理的佛山4G覆盖地图
13
深秋八大关
14
华为P10手机有计算机功能吗,手机教程知识:华为P10支持NFC功能吗 华为P10新功能介绍...
15
什么是QQ空间亲密度?QQ空间亲密度查看方法
PHP1.CN | 中国最专业的PHP中文社区 |
DevBox开发工具箱
|
json解析格式化
|
PHP资讯
|
PHP教程
|
数据库技术
|
服务器技术
|
前端开发技术
|
PHP框架
|
开发工具
|
在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved |
京公网安备 11010802041100号
|
京ICP备19059560号-4
| PHP1.CN 第一PHP社区 版权所有