运算符重载

本文深入探讨了C++中可被重载的操作符,包括优先级、使用方法、规则以及特殊情况。详细介绍了运算符重载的实现方式,特别强调了成员函数与友元函数之间的区别,并对一元与二元运算符、赋值运算符、调用运算符、下标运算符和箭头运算符的重载进行了具体解析。同时,文章还概述了特定操作符的重载规则,如前置和后置增减运算符、赋值运算符的特殊用法。最后,文章提供了几种特殊操作符的重载实例,以及在类设计中如何选择成员函数或友元函数来访问类的私有部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可以被重载的操作符:
+
-
*
/
%
^
&
|
~
!
,
=
<
>
<=
>=
++
--
<<
>>
==
!=
&&
||
+=
-=
/=
%=
^=
&=
|=
*=
<<=
>>=
[]
()
->
->*
new
new[]
delete
delete[]

 

 

 

        
       类的设计者不能声明一个没有出现在上面表格中的重载操作符。
        重载操作符时,操作符优先级不能被改变。与预定义操作符一样,在使用重载操作符时,可以用小括号来改变优先级。操作符预定义的操作数个数不能被改变,例如一元的逻辑非操作符不能被定义为针对某个类对象的二元操作符,否则将导致编译错误。
        对于内置类型,四个预定义的操作符+、- 、* 和& 既可被用作一元操作符也可被用作二元操作符,这两种版本都可以被重载。除了operator()外,对其他重载操作符提供缺省实参都是非法的。

下面是一些运算符重载的规则, 这些规则约束着重载运算符如何实现,但它们并不适用于new和delete运算符。这两个运算符将在后面单独讨论。
1.运算符要遵守它们同内部类型一起使用所指定的优先原则、分组及操作数的个数。
2.单目运算符说明为成员函数不带参数;如果说明为友元函数,要带一个参数。
3.双目运算符说明为成员函数只带一个参量;如果说明为友元函数,要带两个参数。
4.所有的重载运算符,除了赋值(operator=)外均可被派生类继承。如果每个类都需要一个“=”运算符,那么每个类都要明确地定义自己的“=”运算符。

运算符重载时, 运算符重载函数只能定义两种方式,或者作为一个类的成员函数,或者作为友元函数。这两种方式非常类似,但还有很多差别,关键原因在于成员函数具有this指针,而友元函数没有this指针。
不能用友元函数重载的运算符是:
        =,(),[],->

1.一元运算符
一元运算符,不论是前缀还是后缀,都需要一个操作数。
对任何一元运算符α:

(1) 成员函数重载运算符
type X::operator α()
{
       …
    }
    显式调用方式:
objX.operator α()
   隐式调用方式:
    αobjX 或者 objXα
  
  一元运算符重载函数operator α所需的一个操作数通过this指针隐含地传递。因此,它的参数表为空。

(2) 友元函数重载运算符
type operator α(X obj)
     {
       …
      }
     显式调用方式:
     operator α(objX)
     隐式调用方式:
    α objX 或者 objX α

  一元运算符重载函数operator α所需的一个操作数(即所操作的对象)在参数表中。

2.二元运算符
二元运算符,需要两个操作数。

(1)成员函数重载运算符:
type X::operator β(X obj)
{
}
    显式调用方式:
    objX1.operator β(objX2)
    隐式调用方式:
    objX1 β objX2

    二元运算符重载函数operator β所需的第一个操作数通过this指针隐含地传递。第二个操作数通过参数提供,因此,它只有一个参数。

(2) 友元函数重载运算符:
type operator β(X obj1,X obj2)
{
}
    显式调用方式:
    operator β(objX1,objX2)
    隐式调用方式:
   objX1 β objX2
        
    二元运算符重载函数operator β所需的两个操作数都通过参数提供,因此,它有两个参数。

用成员函数重载运算符和用友元函数重载运算符,它们传递参数的方法不一样,也就导致了它们的实现代码不相同。
何时用成员函数,何时用友元函数来访问类的私有部分呢?某些运算必须是成员函数,例如构造函数,析构函数及虚函数。表面上看,没有什么理由一定要用户必须选择成员,或必须选择友元来实现X类对象上的操作。然而,成员函数仅仅能为一个“实际对象”所调用 ,友元无此限制。因此,若运算符的操作需要修改类对象的状态,则它应该是成员函数。而不应是友元。需要左值操作数的运算符(如=,+=,++)的重载最好用成员函数。相反,如果运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则该运算符必须用友元,而不是成员函数。

    
 ################################################################################################################################## 
几种特殊操作符的重载
1.重载++和--
①对于前缀方式++i:
成员函数
X X:operator++();
友元函数
X operator++(X&);
②对于后缀方式i++:
成员函数
X X:operator++(int);
友元函数
X operator++(X&,int);
这时,第二个参数(int)一般设置为0,例如:
        i++; 等价于 i++(0);

2.重载赋值运算符   
        赋值运算符“=”可以被重载,但重载了的运算符函数operator=不能被继承,而且它必须被重载为成员函数,其重载格式为:
        X X::operator=(const X from)
        {
        //复制X的成员
         }
        当用户在一个类中显式地重载了运算符“=”时,称用户定义了类赋值运算。它将一个X类对象from逐域拷贝到赋值号左端的类对象中。
        对于大多数重要的类,有了缺省赋值运算符也许还不够,需要用户自己进行重载,当缺省的类赋值函数不能正确工作时,应当考虑这一问题。

        既然拷贝构造函数和赋值运算符都是把一个对象的数据成员拷贝到另一个对象,两者都配备看来有点奇怪。它们的区别是:拷贝构造函数要创建一个新对象,而赋值运算符则是改变一个已经存在的对象的值。

3.重载调用运算符()
         重载函数调用运算符()时,对应的运算符重载函数为operator().
           运算符”()”不能用友元函数重载,只能采用成员函数重载。
设x为类X的一个对象,则表达式:
        x(arg1,arg2)
  可被解释为:
         x.operator()(arg1,arg2)


4.重载下标运算符[ ]
        与函数调用运算符一样,下标运算符也只能使用成员函数重载。
       重载下标运算符[]时,相应的运算符重载函数为operator[]。
设x为类X的对象,则表达式:
x[y]
解释为:
x.operator[](y)

5.重载运算符->
      
       我们也可以为类类型的对象重载成员访问操作符->,它必须被定义为一个类的成员函数。它的作用是赋予一个类类型与指针类似的行为。
它通常被用于一个代表智能指针(smart pointer)的类类型(这个类的行为很像内置的指针类型,但是可以支持某些额外的功能)。  

###################################################################################################################
类特有的操作符new和delete
1 数组操作符new[]和delete[]

2 定位操作符new()和delete()

注意:
当在构造函数中使用了new进行动态内存分配,在析构函数中调用delete进行动态回收,一定要注意考察缺省的类赋值函数是否能正常工作。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值