首页
技术博客
PHP教程
数据库技术
前端开发
HTML5
Nginx
php论坛
新用户注册
|
会员登录
PHP教程
技术博客
编程问答
PNG素材
编程语言
前端技术
Android
PHP教程
HTML5教程
数据库
Linux技术
Nginx技术
PHP安全
WebSerer
职场攻略
JavaScript
开放平台
业界资讯
大话程序猿
登录
极速注册
取消
热门标签 | HotTags
version
keyword
cSharp
vba
uri
usb
hashcode
actionscrip
byte
perl
integer
triggers
command
int
solr
httprequest
dll
instance
javascript
web
input
bytecode
settings
express
main
utf-8
web3
controller
export
uml
数组
scala
js
join
grid
ip
timestamp
header
emoji
rsa
post
hash
golang
request
list
get
fetch
ascii
chat
cmd
python2
hashtable
merge
c语言
dockerfile
heap
cpython
regex
email
nodejs
iostream
tags
process
erlang
hashset
copy
shell
dagger
tree
substring
typescript
schema
future
python
install
case
client
php
md5
当前位置:
开发笔记
>
编程语言
> 正文
操作符重载浅析
作者:涛之圣首到 | 来源:互联网 | 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
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
USACO 2014 Jan - Moolympics区间记录优化算法
题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ...
[详细]
蜡笔小新 2024-12-27 18:14:31
main
C++ 中的数组与动态数组初始化
本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ...
[详细]
蜡笔小新 2024-12-26 15:38:03
main
VxWorks中的双向链表与环形缓冲应用
本文详细探讨了VxWorks操作系统中双向链表和环形缓冲区的实现原理及使用方法,通过具体示例代码加深理解。 ...
[详细]
蜡笔小新 2024-12-26 13:26:16
main
古代密码变换问题
本题探讨了一种字符串变换方法,旨在判断两个给定的字符串是否可以通过特定的字母替换和位置交换操作相互转换。核心在于找到这些变换中的不变量,从而确定转换的可能性。 ...
[详细]
蜡笔小新 2024-12-28 09:18:22
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
Unity 客户端框架设计:UI管理系统的构建
本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ...
[详细]
蜡笔小新 2024-12-27 10:28:40
main
扫描线三巨头 hdu1928hdu 1255 hdu 1542 [POJ 1151]
学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ...
[详细]
蜡笔小新 2024-12-26 20:04:36
main
Objective-C 编程中的关键语法点
本文探讨了 Objective-C 中的一些重要语法特性,包括 goto 语句、块(block)的使用、访问修饰符以及属性管理等。通过实例代码和详细解释,帮助开发者更好地理解和应用这些特性。 ...
[详细]
蜡笔小新 2024-12-26 19:42:38
main
寻找满足特定条件的整数N的最大和(a+b)
本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ...
[详细]
蜡笔小新 2024-12-26 19:26:18
utf-8
从 .NET 转 Java 的自学之路:IO 流基础篇
本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ...
[详细]
蜡笔小新 2024-12-26 17:37:25
main
文件描述符、文件句柄与打开文件之间的关联解析
本文详细探讨了文件描述符、文件句柄和打开文件之间的关系,通过具体示例解释了它们在操作系统中的作用及其相互影响。 ...
[详细]
蜡笔小新 2024-12-26 14:00:46
main
使用Objective-C和dispatch库实现并发素数计算
本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ...
[详细]
蜡笔小新 2024-12-28 08:44:35
main
新浪笔试题
1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ...
[详细]
蜡笔小新 2024-12-27 19:32:17
涛之圣首到
这个家伙很懒,什么也没留下!
Tags | 热门标签
version
keyword
cSharp
vba
uri
usb
hashcode
actionscrip
byte
perl
integer
triggers
command
int
solr
httprequest
dll
instance
javascript
web
input
bytecode
settings
express
main
utf-8
web3
controller
export
uml
RankList | 热门文章
1
详解Android JetPack之LiveData的工作原理
2
Android制作一个锚点定位的ScrollView
3
Android使用ViewFlipper实现图片上下自动轮播的示例代码
4
Android Studio实现QQ的注册登录和好友列表跳转
5
Android实现可输入数据的弹出框
6
Android弹出窗口实现方法
7
Android如何自定义EditText下划线?
8
Android的Activity加载方式实例分析
9
Android持久化技术之SharedPreferences存储实例详解
10
Android布局之LinearLayout自定义高亮背景的方法
11
Android百度地图实现搜索和定位及自定义图标绘制并点击时弹出泡泡
12
Android实现粒子雨效果
13
Android Notification通知解析
14
7种形式的Android Dialog使用实例
15
Listview加载的性能优化是如何实现的
PHP1.CN | 中国最专业的PHP中文社区 |
DevBox开发工具箱
|
json解析格式化
|
PHP资讯
|
PHP教程
|
数据库技术
|
服务器技术
|
前端开发技术
|
PHP框架
|
开发工具
|
在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved |
京公网安备 11010802041100号
|
京ICP备19059560号-4
| PHP1.CN 第一PHP社区 版权所有