当运算符作用于类类型的运算对象时,可以通过运算符重载重新定义该运算符的含义,合适的使用运算符重载可以提高代码的可读性!
运算符重载
重载运算符函数的参数数量于该运算符作用的运算对象数量一样多,但若该运算符重载函数是成员函数,则它的第一个运算对象绑定到this指针上,所以成员运算符函数的(显式)参数数量比运算对象的数量少一个。
Tips:
- 1.对于一个运算符重载函数来说,它的运算对象不能全是内置类型,因为这样会导致原来正确的运算式不能得到正确的运算(二义性)。
- 2.只能重载已有的运算符,不能发明新的运算符号。
-
3.部分运算符不能被重载,见下图 :
P1 - 4.某些运算符不应该被重载(尽管它们被可以重载):逻辑与,逻辑或和逗号运算符,因为它们的运算对象求值顺序规则重载后不能被保留下来看,并且对"||"与"&&"来说,重载版本无法保留它们的短路求值属性。
成员函数还是非成员函数
当我们定义重载的运算符时,需要考虑是将其声明为类的成员函数还是非成员函数,下面给出《C++Primer》上给出的判断准则:
- 1.赋值("=")、小标("[ ]")、调用("()")和成员访问箭头("->")运算符必须是成员。
- 2.复合赋值运算符一般来说应该是成员,但并非必须,这一点与赋值运算符略有不同。
- 3.改变对象状态的运算符或者与给定类型密切相关的运算符,如递增、递减和解引用运算符,通常应该是成员。
- 4.具有对称性的运算符可能转换为任意一端的运算对象,例如算术、相等性、关系和位运算符等,因此它们通常应该是普通的非成员函数。
下面通过重载输入输出运算符来熟悉一下上面的内容:
重载输入输出运算符
#include <iostream>
using namespace std;
class Sales_data{
private:
int a,b,c;
//输出一个对象的数据成员不会改变对象的状态,所以这里用const Sales_data&
friend ostream &operator<<(ostream &os,const Sales_data& a);
//输入的值会改变对象的数据成员,所以这里不用const
friend istream &operator>>(istream &is,Sales_data& a);
public:
Sales_data():a(0),b(0),c(0){};
Sales_data(int a,int b,int c):a(a),b(b),c(c){};
~Sales_data(){cout<<"~Sales_data"<<endl;}
};
ostream &operator<<(ostream &os,const Sales_data& a){
os<<a.a<<" "<<a.b<<" "<<a.c<<endl;
return os;
}
istream &operator>>(istream &is, Sales_data &a){
int t;
is >> a.a>>a.b>>t;
//这个if语句用来检查输入是否成功
if(is)
a.c = a.a + a.b + t;
//如果不成功,对象被赋予默认的状态
else
a = Sales_data();
}
int main()
{
Sales_data b(1,2,3);
cin>>b;
cout<<b;
return 0;
}
对于上面这段代码,我们可以看出,输入输出运算符必须是非成员函数,这两个运算符重载函数的第一个参数都是非常量流的引用,另外,它们都访问了Sales_data对象的私有成员,所以我们需要将它们声明为友元。
网友评论