重载运算符的函数一般格式:
函数类型operator运算符名称(形参表列)
{对运算符的重载处理}
重载运算符遵循规则:
(1)C++不允许自定义新的运算符,只能重载已有运算符。
(2)五种运算符不能重载:“.”、“.*”、“::”、“sizeof”、“?:”
(3)重载不能改变运算对象个数,即双目仍为双目、单目仍为单目。
(4)重载不能改变运算符优先级。
(5)重载不能改变运算符结合方式。
(6)重载运算符的函数无默认参数。
(7)重载的运算符必须和用户定义的对象一起使用,运算符参数(操作的对象)中至少应有一个是类对象(或类对象的引用)。
(8)对于类对象操作的运算符一般必须重载,但“=”、“&”不必用户重载。
(9)运算符重载函数可以是类的成员函数,可以是类的友元函数,可以是普通函数。
(10)对于运算符重载函数“=”、“[]”、“()”必须定义为类成员函数,“<<”、“>>”、“(类型)”不能定义成类的成员函数,一般单目运算符重载为成员函数,双目运算符重载为友元函数(若为成员函数交换律将不适用)。
(11)“>>”、“<<”的重载函数形式:
istream & operator>>(istream&,自定义类 &);
ostream & operator<<(istream&,自定义类 &);
重载函数的形式注定了其没有隐含参数*this,自然也就不能是成员函数。
(12)类型转换的重载:
<1>转换构造函数:其他类型数据转化成一个类对象,要求只有一个形参。
形式:类名(类型名 类型形参){类的初始化语句}
<2>类型转化函数(类型转化运算符重载函数):对象转化成其他类型的数据,要求不能有参数。
形式:operator 类型名(){实现转换的语句}
对于第七条、第九条单独举例说明:
<1>运算符重载函数为类的成员函数
class jia
{
int i;
public:
jia(int a):i(a){}
int operator +(int j)
{
int s;
s=i+j;
return s;
}
};
int main()
{
jia tt(5);
cout<<tt+5<<endl;
}
疑问:代码中重载运算符“+”的参数为(int j),不是与第七条要求的运算符参数(操作的对象)中至少应有一个是类对象(或类对象的引用)相违背吗?
其实,并没有违背。双目运算符“+”应对应两个参数,代码中的(int j)为其中一个参数。
由于重载运算符函数为类中的成员函数,所以另一个参数成为了隐含参数(jia *this),运算符函数通过this指针隐式地访问类中成员。
注意:代码中的tt+5,编译系统把它解释成 tt.operator +(5) ,即代码中tt+5写成tt.operator+(5)运行也通过,tt.operator中含隐含参数(jia *this)。
若写成5+tt则无法调用5.operator+(tt),所以不能写成5+tt,类中的成员函数作为重载运算符函数则一般要求运算符左侧是类的对象(即隐含参数作为第一个参数),因为要通过对象才能调用类中的重载运算符函数,当然对于一些单目运算符(如前置“++”)则对象要放在运算符后面。
<2>运算符重载函数为友元函数
class jia
{
int i;
public:
jia(int a):i(a){}
friend int operator +(jia &t,int j);//也可以不用引用,引用只是为了减少内存开销
};
int operator +(jia &t,int j)
{
int s;
s=t.i+j;
return s;
}
int main()
{
jia tt(5);
cout<<tt+5<<endl;
}
非类的成员函数所以这里operator +的两个参数都变成了显式参数,不能缺省。
代码中的tt+5,编译系统把它解释成operator(tt,5),即代码中tt+5可以写成 operator(tt,5)运行也通过,同样这里也不能写成5+tt。
<3>运算符重载函数为普通函数
只有在极少的情况下才能使用普通函数进行重载,原因在于普通函数不能直接访问类中的私有成员。
对于第十一条举例说明并解释重载函数形式:
class complex
{
public:
complex(){real=0,imag=0;}
complex(double r,double i):real(r),imag(i){}
friend ostream& operator << (ostream&,complex&);
private:
double real;
double imag;
};
ostream& operator <<(ostream& output,complex& c)
{
output<<"("<<c.real<<"+"<<c.imag<<"i)"<<endl;
return output; //作用是为了能连续向输出流插入数据
}
int main()
{
complex c(6,10);
cout<<c;
}
cin为istream类的对象,cout为ostream类的对象。
代码中的“cout<<c”编译系统将其解释为“operator<<(cout,c)”。
return output是为能连续向输出流插入数据,output是ostream的对象,它是实参cout的引用,return output即为return cout。
若执行cout<<c2<<c3;则先处理cout<<c2,即(cout<<c2)<<c3;
而执行cout<<c2得到的结果就是具有新内容的流对象cout,因此(cout<<c2)<<c3相当于cout(新值)<<c3;因而需再次调用"<<"重载函数,所以"<<"重载函数的第一个参数类型和函数类型都为ostream类型的引用,为的就是返回cout的当前值以便连续输出。
对于第十二条举例说明:
<1>转换构造函数
class convert
{
public:
convert(double r) //转换构造函数(其他类型数据转化成一个类对象),要求只要一个形参
{real=r,imag=0;}
friend double operator +(convert&,convert&);
private:
double real;
double imag;
};
double operator +(convert& c1,convert& c2)
{
double a;
a=c1.real+c2.real;
return a;
}
int main()
{
double d;
convert c1(0);
c1=convert(3.6); //convert(3.6)建立了一个无名的对象
d=c1+3.5;
cout<<d;
}
程序出错,原因:d=c1+3.5;//这个语句中的3.5会转换成一个convert型的临时变量,而double operator +(convert& c1,convert& c2)函数中的参数是个引用,而引用不能引用临时变量的。
两种解决方法:
1、将引用删除,即改成:
friend double operator +(convert,convert); //声明中删除了&
double operator+(convert c1,convert c2){ } //对于定义中也删除&
2、将引用改成常引用,保留了引用减少内存开销的好处,即改成
friend double operator +(const convert&,constconvert&); //声明中加入了const
double operator+(const convert& c1,const convert& c2){ } //对于定义中也加入const
程序运行成功。
实现机理:d=c1+3.5;系统去找发现重载了“+”,但对应重载的参数是两个对象,系统又会去找发现有转换构造函数,则自动调用convert(3.5)将其转换成convert类的临时对象,从而实现了c1+3.5。
<2>类型转换函数
class convert
{
public:
convert(double r,double i):real(r),imag(i){}
operator double() //类型转化函数(对象转化成其他类型的数据),要求不能有参数
{return real;}
private:
double real;
double imag;
};
int main()
{
convert c(3.6,0);
double d;
d=c1+3.5;
cout<<d;
}
实现机理:d=c1+3.5;系统去找发现有类型转换函数,则自动调用operatordouble()将convert类对象c1转换成double型临时变量,从而实现了c1+3.5。
若上面两种转换合并都一个程序中,结果如何?
class convert
{
public:
convert(double r) //转换构造函数(其他类型数据转化成一个类对象),要求只要一个形参
{real=r,imag=0;}
friend double operator +(convert,convert);
operator double()
{return real;}
private:
double real;
double imag;
};
double operator +(convert c1,convert c2)
{
double a;
a=c1.real+c2.real;
return a;
}
int main()
{
double d;
convert c1(0);
c1=convert(3.6); //convert(3.6)建立了一个无名的对象
d=c1+3.5;
cout<<d;
}
程序出错,原因就是同时存在两种转换方法,从而导致冲突。