【C/C++学习】之十三、运算符重载
= () [] —> 只能重载为成员函数
+= -= /= *= |= ~= %= >>= <<= 建议重载为成员函数
所有其他运算符 建议重载为全局函数
. 操作符不能重载
不能重载目前C++运算符集合中没有的符号
原因:1。难以理解 2.难以确定优先级
对已经存在的运算符进行重载时,不能改变优先级规则,否则将引起混乱。
运算符重载的一般形式如下:
返回类型 operator 运算符符号(参数说明) { .... }
函数重载的时候,只有一个参数的运算符叫做一元运算符,有两个参数的运算符叫做二元运算符。
当你在类中重载运算符的时候,如果是一元运算符就不需要参数了,二元运算符只有一个右侧参数,因为对象自己就作为左侧参数。
对于全局函数和成员函数:
运算符 |
建议 |
所有的一元运算符 | 建议重载为成员函数 |
=、()、[]、-> | 只能重载为成员函数 |
+=、-=、/=、*=、&=、|=、~=、%=、>>=、<<= | 建议重载为成员函数 |
所有其他运算符 | 建议重载为全局函数 |
下面看一下重载运算符的规则:
1、只能重载语言自身已有定义的运算符。
2、有5个运算符不能重载,分别是类属性运算符“."、成员指针运算符”*“、作用域分辨符"::"、”sizeof“运算符和三目运算符"?:'。 还有就是不能重载C++运算符集合中没有的符号,因为他们难以理解,难以确定优先级。
3、不能改变运算符的操作个数。
4、不能改变运算符的原有优先级。
5、不能改变运算符原有的结合特性。
6、不能改变运算符对预定义类型数据的操作方式。
{优先级不变,结合性不变,操作数不变,语法结构不变}
在类中,有成员函数和友元函数两种,我们可以使用友元函数重载运算符。也就是当操作符定义为非成员函数时,通常必须将他们设置为所操作类的友元。
当我们使用友元函数重载运算符时,由于没有this执着呢,因此,函数的参数是引用类型:
A operator +(const A &a1, const A &a2);
当我们使用友元函数重载双目运算符时,两个操作数都要传递给运算符函数。
当我们使用友元函数重载单目运算符时,需要一个显示的操作符。
我们在实际开发中,单目运算符建议重载为成员函数,而双目运算符建议重载为友元函数,通常情况下双目运算符重载为友元函数比重载为成员函数更方便,但是有时双目运算符必须重载为成员函数:如:赋值运算符, 如果将该运算符重载为友元函数,将会出现与赋值予以不一致的地方。
但是当我们用友元函数重载”++“和”--“运算符的时候又会怎样呢?
运算符”++“和”--“都是对单值操作数产生影响的,因此使用成员函数重载这两个运算符的成员函数通常返回指针this。
因为友元函数没有this指针,因此不能引用this指针作为指向的对象。使用友元函数重载这两个操作符时,应采用引用参数传递数据。
如:
a operator ++(a &op) { ++op.x; ++op.y; return op; }
说到这里,我们就来看一下成员运算符函数和友元运算符函数的区别:
1、格式不同
友元函数:
<类型说明符> operator <运算符>(<参数表>) { 函数体 }成员函数:
<类型说明符> 类名::operator <运算符>(<参数表>) { 函数体 }
2、参数表的结构不同
在成员运算符函数的参数表中,如果运算符时单目的,则参数为空,此时当前对象作为运算符的一个操作数,通过this指针隐含地传递给函数;
如果运算符时双目的,则参数表中有一个操作数,该操作数作为运算符的右操作参数,此时当前对象作为运算符的左操作数,它是由this指针隐含地传递给函数的。
而和成员函数不同,友元运算符函数不属于任何类对象,其没有this指针。如果重载的是双目运算符,则参数表中有两个操作数;如果重载的是单目运算符,则参数表中只有一个操作数。
下面来看一下重载NEW和DELETE运算符,数组下标运算符:
1、NEW和DELETE运算符
有两种方式重载:
1、覆盖默认定义的全局方式 2、只针对一个类的局部方式。 在实际应用中,一般采用后一种方式。
void* operator new(size_t size) { 使用new运算符分配size大小的存储空间。 }
void* operator delete(void* pointer) { 使用delete运算符释放指针pointer所指向的存储空间 }
上面是new和delete运算符的重载方式, 其中pointer指针指向一个待释放的内存空间, 我们调用delete()函数释放该指针所指向的内存空间。
我们在类中重载的new和delete运算符只能用于动态生成各个对象,而不能用于生成对象数据、自动对象和静态对象等。
重载全局的new和delete运算符需要在类的外部定义,定义格式与在类中定义的格式基本相同,只是不带类作用域。重载全局的new和delete运算符时需要谨慎,一旦定义为全局,在整个程序中只要是使用new和delete运算符的操作都将使用该重载的定义。
2、数组下标运算符
我们知道数组的大小是不能确保的,所以对数组元素进行存取范围的检查是不允许的,所以在操作数组动态赋值时经常会发生越界。所以我们在这里来说一种安全的方案定义重载的运算符"[]";
我们在重载下标运算符的时候要注意:
1、该函数只能带一个参数,不能带多个参数。
2、得重载为友元函数,必须是非static类的成员函数。
下面再来看一下重载输入输出操作符:
ostream& operator<<(ostream& out, const A& s) { out << s.a <<............. return out; } instream& operator>>(istream& in, A& s) { double si; in >> s.a..................... if (in) ... else ... return in; }
最后要注意的是不要滥用操作符重载。
2012/10/11
jofranks 于南昌