运算符重载为成员函数
当C++不存在某些现实中存在的运算(比如复数的加减)或不存在满足我们要求的运算符时,我们可以对运算符进行重载。
重载为成员函数的运算符函数定义形式为:
函数类型 operator 运算符(形参)
{
...
}
此时参数即形参的个数=原操作数-1(后置++,–除外,因为这两个需要额外加一个int类型的形参来区分是前置或还是后置运算符)
以下两种情况运算符不能重载为成员函数:
1.当重载为成员函数的运算符时,左操作数一定是类的对象,不能为其他类型,比如重载实数+复数时,实数不是自定义的复数类,不能采用重载为类成员函数的形式。
2.当左操作数是类成员,但是这个类不是由自己定义的,比如是类库中的类,此时,不能直接在此类中增加成员函数对运算符进行重载。
注:存在必须重载为类成员函数的操作符:赋值(=),下标 ([ ]),调用(( )),成员访问(->)。 参考https://blog.csdn.net/qq_29344757/article/details/78820189
双目运算符重载
双目运算符重载规则:如果要重载运算符O为类成员函数,使之能够实现表达式 oprd1 O oprd2,其中oprd1为A类对象,那么运算符O应该重载为A类的成员函数,形参类型应该是oprd2所属类型。
经重载后,表达式oprd1 O oprd2就相当于oprd1.operator O(oprd2);
以下程序对复数的双目加减运算进行了重载,实现了复数的加减:
class Complex{
public:
Complex(double r=0.0,double i=0.0):real(r),imag(i){
}
Complex operator +(const Complex &c2) const{
return Complex(real+c2.real,imag+c2.imag);
}
Complex operator -(const Complex &c2) const{
return Complex(real-c2.real,imag-c2.imag);
}
void display(){
cout<<"("<<real<<","<<imag<<")"<<endl;
}
private:
double real;
double imag;
};
int main(){
Complex c1(5,2);Complex c2(2,10);Complex c3;
c1.display();c2.display();
c3=c1+c2;
c3.display();
c3=c1-c2;
c3.display();
return 0;
}
单目运算符重载
前置的单目运算符重载规则:
如果要重载O为类成员函数,使之能够实现表达式 O oprd,其中oprd为A类对象,那么运算符O应该重载为A类的成员函数,形参类型应该为空。
经重载后,表达式O oprd就相当于oprd.operator O();
后置的单目运算符重载规则:
与前置规则一致,只是必须具有一个int类型的形参。
经重载后,表达式oprd O就相当于oprd.operator O(int);
注:这个int类型的形参只是用来区分是前置还是后置运算符,无参数为前置,有参数为后置,且这个参数在函数体中不能够使用。
在以下代码中实现对时钟的读秒++运算:
class Clock{
public:
Clock(int hour,int minute,int second){
if(0<=hour&&hour<24&&0<=minute&&minute<60&&second>=0&&second<60){
this->hour=hour;
this->minute=minute;
this->second=second;
}
else{
cout<<"time is worry"<<endl;
}
}
void showTime(){
cout<<hour<<":"<<minute<<":"<<second<<endl;
}
Clock& operator ++(){ //前置++直接输出结果,不存在中间变量,返回一个引用能减小消耗
second++;
if(second>=60){
second-=60;minute++;
if(minute>=60){
minute-=60;hour=(hour+1)%24;
}
}
return *this;
}
Clock operator ++(int){//后置++需要返回一个局部变量(+1前的值),因此不能返回引用
Clock old =*this;
++(*this);
return old;
}
private:
int hour,minute,second;
};
int main(){
Clock c(23,59,59);
c.showTime();
(c++).showTime();
(++c).showTime();
return 0;
}
从运行结果来看可知对++运算进行了重载,使之实现了时钟的+1。同时,也加深我们对i++和++i的理解,i++是对现有结果输出,同时+1;++i则是对现有结果+1之后再输出。
运算符重载为非成员函数
重载为非成员函数的运算符重载规则:
1.函数的形参列表表依次从左向右的的次序排列各操作数;
2参数的个数=原操作数个数(后置的++,–等除外,因为要加一个int类型的形参区分前置还是后置);
3.至少应该有一个自定义类型的操作数,不能两个操作数都是基本类型的,比如不能重载一个两个实数的加法,这是不允许的。
双目运算符经重载后,表达式oprd1 O oprd2就相当于operator O(oprd1,oprd2);
前置单目运算符重载后,表达式O oprd就相当于operator O(oprd);
后置单目运算符重载后,表达式oprd O就相当于operator O(oprd,0);
看以下例子完成对复数的加减重载为非成员函数:
class Complex{
public:
Complex(){
}
Complex(int a,int b):real(a),imag(b){
}
friend Complex operator +(const Complex &c1,const Complex &c2 );//声明为友元使得能够访问类的私有变量
friend Complex operator -(const Complex &c1,const Complex &c2 );
friend ostream & operator <<(ostream &out,const Complex &c );
void show(){
cout<<real<<","<<imag<<endl;
}
private:
int real;
int imag;
};
Complex operator +(const Complex &c1,const Complex &c2 ){
return Complex(c1.real+c2.real,c1.imag+c2.imag);
}
Complex operator -(const Complex &c1,const Complex &c2 ){
return Complex(c1.real-c2.real,c1.imag-c2.imag);
}
ostream & operator <<(ostream &out,const Complex &c ){
out<<"("<<c.real<<","<<c.imag<<")";
return out;
}
int main(){
Complex c(1,2);
Complex d(2,3);
Complex e;
e=c+d;
cout<<e<<endl;
return 0;
}
上述程序中将运算符重载为非成员函数,并将其声明为复数类的友元,使得能在在类外访问类的私有成员,其实也可以通过类的共有接口去访问类的私有成员,但是声明为友元运算的效率会高一些。
同时对双目<<运算进行了重载,实现了直接输出复数的形式。注意在重载时,左操作数是std::ostream的引用,右操作数是复数类的常引用,返回std::ostream引用实现多级的输出。