操作符重载(小原则)
一.运算符重载的含义与定义方式
l C++已有的运算符只适合处理C++的基本数据类型。
l C++允许重新定义已有的运算符(运算符重载),以便它能处理程序员定义类型(类类型)。
l 运算符重载就是赋予已有的运算符多重含义。运算符重载与函数重载类似,是它的特殊类型。
l C++通过重新定义运算符,使它能够用于特定类的对象执行特定的功能。
l 通过对+,-,*,/运算符的重新定义,使它们可以完成复数、分数等不同类的对象的加、减、乘、除运算操作。增强了C++语言的扩充能力。
l 先创建一个运算符函数,一般定义成类的成员函数或友元函数。
二.重载一个运算符原则:
1.不能改变运算符的初始意义。
2.不能改变运算符的参数数目。如重载运算符+时只用一个操作数是错误的。
3.运算符函数不能包括缺省的参数。
4.绝大部分C++运算符都可以重载,除以下的例外:
. :: .* ?
5.除赋值运算符外,其它运算符函数都可以由派生类继承。
6.运算符重载不改变运算符的优先级和结合性,也不改变运算符的语法结构,即单目、双目运算符只能重载为单目、双目运算符。
7.运算符的重载实际上是函数的重载。编译程序对运算符重载的选择,遵循函数重载的选择原则。当遇到不很明显的运算符时,编译程序将去寻找参数匹配的运算符函数。
8.运算符重载可使程序更简洁,使表达式更直观,增强可读性。但使用不宜过多。
9.重载运算符含义必须清楚:
如有一个类Time,它有三个数据成员时、分、秒
calss Time{
public:
Time() {hours=minutes=seconds=0;}
Time(int h,int m,int s){ hours=h; minutes=m; seconds=s;}
private:
int hours, minutes, seconds;
};
Time t1(8,10,20), t2(9,15,30), t3;
t3=t1+t2;
这里加法(+)运算用于类Time的对象,就是含义不清的。所以不能给类Time定义重载运算符+。
三.运算符重载函数的两种形式:
成员函数形式和友元函数形式,他们都可访问类中的私有成员。
1.重载为类的成员函数
1)X类中重载一元运算符@
返回类型 X::operator@( )
{ … }
不指定参数,因为它已带有一个隐含的this参数,对X类的一个对象obj:
表达式 C++编译器的解释
@obj operator @(obj)
obj@ operator @(obj,0)
2) X类中重载二元运算符@
返回类型 X::operator@(参数说明)
{ … }
由于类的成员函数带有一个this参数,此时只能指定一个参数,对obj对象:
表达式 C++编译器的解释
obj1@obj2 obj1·operator@(obj2)
在多数情况下,将运算符重载为类的成员函数和类的友元函数都是可以的。但成员函数运算符与友元函数运算符也具有各自的一些特点:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
例:给复数运算符重载的四则运算符。复数由实部和虚部构造,定义一个复数类,再在类中重载复数四则运算的运算符。
#include<iostream.h>
class complex
{ private:
float real,imag;
public:
complex(float r=0,float i=0);
complex operator+(complex &c);
complex operator-(complex &c);
friend void print(complex &c);
};
complex::complex(float r,float i)
{ real=r; imag=i; }
complex complex::operator+(complex &c)
{ float r=real+c.real; float i=imag+c.imag;
return complex(r,i) ; }
complex complex::operator-(complex &c)
{ float r=real-c.real; float i=imag-c.imag;
return complex(r, i) ; }
void print(complex &c )
{ cout<<'('<<c.real<<','<<c.imag<<')'<<endl; }
void main( )
{ complex c1(2.5,3.7), c2(4.2,6.5) ;
complex c;
c=c1-c2; //c=c1·operator-(c2)
print(c);
c=c1+c2; //c=c1·operator+(c2)
print(c);
}
该程序中定义一个complex类,定义了2个成员函数作为运算符重载函数。
c1+c2编译程序解释为:c1.operator+(c2)
c1、c2是complex 类的对象。operator+()是运算符+的重载函数。
该运算符重载函数仅有一个参数c2。当重载为成员函数时,双目运算符仅有一个参数。
对单目运算符,重载为成员函数时,不能再显式说明参数。
重载为成员函数时,总是隐含了一个参数,即this指针,它是指向调用该成员函数对象的指针。
在重载运算符函数中,operator +( )中参数用引用传递而不用指针传递。
因为指针传递存在程序的可读性问题。如操作符重载声明为:
complex operator +( complex *c);
则调用时
complex c1(2.0,3.0),c2(4.0,-2.0),c3;
c3=&c1+&c2; 会认为是c1的地址和c2的地址相加
而声明为complex operator +(const complex &c);
则 c3=c1+c2;
2. 重载为友元函数
运算符重载函数还可以为友元函数。当重载为友元函数时,没有隐含的参数this指针。这样对双目运算符,友元函数有2个参数,对单目运算符,友元函数有1个参数。但有些运算符不能重载为友元函数,它们是:=、()、[]、->。
1) X类中重载一元运算符@
返回类型 operator@(X&obj )
{ … }
只能为友元运算符指定一个参数,对X类的一个对象obj:
表达式 C++编译器的解释
@obj operator @(obj)
obj@ operator @(obj,0)
2) X类中重载二元运算符@
返回类型 operator@(参数说明1,参数说明2)
{……}]
两个参数中必须至少有一个是X类类型,设有对象obj1,obj2
表达式 C++编译器的解释
obj1@obj2 operator @(obj1,obj2)
例:用友元函数代替成员函数编上述程序:
#include<iostream.h>
class complex
{ private:
float real,imag;
public:
complex(float r=0,float i=0);
friend complex operator+(complex &c1,complex &c2);
friend complex operator-(complex &c1,complex &c2);
friend void print(complex &c);
};
complex::complex(float r,float i)
{ real=r; imag=i; }
complex operator+(complex &c1,complex &c2)
{ float r=c1.real+c2.real; float i=c1.imag+c2.imag;
return complex(r,i) ; }
complex operator-(complex &c1,complex &c2)
{ float r=c1.real-c2.real; float i=c1.imag-c2.imag;
return complex(r, i) ; }
void print(complex &c )
{ cout<<'('<<c.real<<','<<c.imag<<')'<<endl; }
void main( )
{ complex c1(2.5,3.7), c2(4.2,6.5) ;
complex c;
c=c1-c2; //c=c1·operator-(c2)
print(c);
c=c1+c2; //c=c1·operator+(c2)
print(c);
}
双目运算符重载为成员函数时,仅有一个参数,另一个被隐含;
重载为友元函数时,有两个参数,没有隐含参数;
c1+c2编译程序解释为:operator+( c1,c2)
调用如下函数,进行求值,
complex operator +(const complex &c1,consrt complex &c2)
结论1:对二元运算符,将它重载为一个友元函数比重载为一个成员函数要便于使用。作为一个友元函数,二元运算符不要求第一个参数一定为某类的对象。
结论2:对一元运算符,将它重载为一个成员函数最恰当。重载为友员函数也可以。
例:
#include <iostream.h>
class A{
public:
A(){X=Y=0;}
A(int i,int j){X=i;Y=j;}
A(A &p){X=p.X;Y=p.Y;}
A& operator =(A &p);
int getX(){return X;}
int getY(){return Y;}
private:
int X,Y;
};
A& A::operator =(A &p)
{
X=p.X;
Y=p.Y;
cout<<"Assignment operator called./n";
return *this;
}
void main()
{
A a(7,8);
A b;
b=a;
cout<<b.getX()<<","<<b.getY()<<endl;
}
Assignment operator called.
7,8
该程序中,在类A中定义了一个赋值运算符函数,被定义为成员函数。
b=a解释为: b.operator=(a)
调用下列函数:A& A::operator=(A &p)完成赋值操作。