1、运算符重载
- 运算符重载,就是对已有的运算符(C++中预定义的运算符)赋予多重的含义,使同一运算符作用于不同类型的数据时导致不同类型的行为
- 运算符重载的目的是:扩展C++中提供的运算符的适用范围,使之能作用于对象
- 同一个运算符,对不同类型的操作数,所发生的行为不同
2、运算符重载的形式
- 运算符重载的实质是函数重载
- 可以重载为普通函数,也可以重载为成员函数
- 把含运算符的表达式转换成对运算符函数的调用
- 把运算符的操作数转换成运算符函数的参数
- 运算符被多次重载时,根据实参的类型决定调用哪个运算符函数
返回值类型 operator 运算符(形参表){
……
}
注:重载为成员函数时 , 参数个数为运算符目数减一 ,重载为普通函数时 , 参数个数为运算符目数
class Complex{
public:
double real,imag;
Complex( double r = 0.0, double i= 0.0 ):real(r),imag(i) { }
Complex operator-(const Complex & c);
};
Complex operator+( const Complex & a, const Complex & b){
return Complex( a.real+b.real,a.imag+b.imag); // 返回一个临时对象
}
Complex Complex::operator-(const Complex & c){
return Complex(real - c.real, imag - c.imag); // 返回一个临时对象
}
int main(){
Complex a(4,4),b(1,1),c;
c = a + b; // 等价于c=operator+(a,b);
cout << c.real << "," << c.imag << endl;
cout << (a-b).real << "," << (a-b).imag << endl; //a-b 等价于a.operator-(b)
return 0;
}
3、赋值运算符“=”只能重载为成员函数
对运算符进行重载的时候,好的风格是应该尽量保留运算符原本的特性
class String {
private:
char * str;
public:
String ():str(new char[1]) { str[0] = 0;}
const char * c_str() { return str; };
String & operator = (const char * s);
String::~String( ) { delete [] str; }
};
String & String::operator = (const char * s){ // 重载“=”得 以使得 obj = “hello” 能够成立
if( this == & s) //存在s = s 情况
return * this;
str = new char[strlen(s)+1];
strcpy( str, s);
return * this;
}
4、运算符重载为友元函数
- 一般情况下,将运算符重载为类的成员函数,是较好的选择。
- 但有时,重载为成员函数不能满足使用要求,重载为普通函数,又不能访问类的私有成员,所以需要将运算符重载为友元
class Complex{
double real,imag;
public:
Complex( double r, double i):real(r),imag(i){ };
Complex operator+( double r );
};
Complex Complex::operator+( double r ){ //能解释 c+5
return Complex(real + r,imag);
}
经过上述重载后:
Complex c ;
c = c + 5; 有定义,相当于 c = c.operator +(5);
但是:
c = 5 + c; 编译出错
所以,为了使得上述的表达式能成立,需要将 + 重载为普通函数
但是普通函数又不能访问私有成员,所以,需要将运算符 + 重载为友元。
class Complex{
//...
friend Complex operator + (double r,const Complex & c);
};
5、流插入运算符和流提取运算符的重载
ostream & ostream::operator<<(int n/const char * s ){
…… // 输出n 的代码
return * this;
}
cout << 5 << “this”;
cout.operator<<(5).operator<<(“this”); //本质上的函数调用的形式
6、自增,自减运算符和类型强制转换运算符的重载
自增运算符++、自减运算符--有前置/后置之分,为了区分所重载的是前置运算符还是后置运算符,C++规定:
(1)前置运算符作为一元运算符重载
- 重载为成员函数:
T & operator++();
T & operator--();
- 重载为全局函数:
T1 & operator++(T2);
T1 & operator—(T2);
(2)后置运算符作为二元运算符重载,多写一个没用的参数:
- 重载为成员函数:
T operator++(int);
T operator--(int);
- 重载为全局函数:
T1 operator++(T2,int );
T1 operator—( T2,int);
class CDemo {
private :
int n;
public:
CDemo(int i=0):n(i) { }
CDemo & operator++(); // 用于前置形式
CDemo operator++( int ); // 用于后置形式
operator int ( ) { return n; }
friend CDemo & operator--(CDemo & );
friend CDemo operator--(CDemo & ,int);
};
CDemo & CDemo::operator++(){ //前置 ++
n ++;
return * this;
} // ++s即为: s.operator++();
CDemo CDemo::operator++( int k ){ //后置 ++
CDemo tmp(*this); // 记录修改前的对象
n ++;
return tmp; // 返回修改前的对象
} // s++即为: s.operator++(0);
CDemo & operator--(CDemo & d){ // 前置--
d.n--;
return d;
} //--s即为: operator--(s);
CDemo operator--(CDemo & d,int){ // 后置--
CDemo tmp(d);
d.n --;
return tmp;
} //s--即为: operator--(s, 0);
(3)operator int ( ) { return n; }
- int 作为一个类型强制转换运算符被重载
Demo s;
(int) s ; //等效于 s.int();
- 类型强制转换运算符被重载时不能写返回值类型,实际上其返回值类型就是该类型强制转换运算符代表的类型
7、运算符重载的注意事项
- C++不允许定义新的运算符 ;
- 重载后运算符的含义应该符合日常习惯;
- 运算符重载不改变运算符的优先级;
- 以下运算符不能被重载:“.”、“.*”、“::”、“?:”、sizeof;
- 重载运算符()、[]、->或者赋值运算符=时,运算符重载函数必须声明为类的成员函数。