今天看C++primier第五版494页下面有一段叙述:
与iostream标准库库兼容的输入输出运算符必须是普通的非成员函数,而不能是类的成员函数。否则,它们的左侧运算对象将是我们类的一个对象。
原因倒是非常简单,因为如果重载函数是作为类中的一个非静态成员的话,就必须通过一个已经被实例化的类来调用,如果仅仅是作为一个友元函数的话,那么直接调用就可以了。
那么对于前者,很明显地可以知道的是由于是作为类中的一个非静态成员,自然也就有隐式定义的this指针,所以在定义和声明函数的时候,参数自然而然地就少了一个,但是引用该函数的时候就必须要划定该函数的作用域是在某个已经被实例化的域上。
对于作为友元的后者,参数而言的话就多了一个。以位计算符的重载为例:
首先是作为类成员函数:
- #include<iostream>
- using namespace std;
- class Date{
- public:
- Date(){
- }
- Date(int y,int m,int d){
- year=y;
- month=m;
- day=d;
- }
- const Date& operator<<(const Date &d) const;
- private:
- int year,month,day;
- };
- const Date& Date::operator <<(const Date& d) const
- {
- const char sep=‘\t’;
- cout<<”year:”<<d.year<<sep<<“month:”<<d.month<<sep<<“day:”<<d.day<<endl;
- return *this;
- }
- int main(){
- Date b;
- Date a(2016,12,12);
- Date c(2011,11,11);
- b<<a<<c;
- return 0;
- }
#include<iostream>
using namespace std;
class Date{
public:
Date(){
}
Date(int y,int m,int d){
year=y;
month=m;
day=d;
}
const Date& operator<<(const Date &d) const;
private:
int year,month,day;
};
const Date& Date::operator <<(const Date& d) const
{
const char sep='\t';
cout<<"year:"<<d.year<<sep<<"month:"<<d.month<<sep<<"day:"<<d.day<<endl;
return *this;
}
int main(){
Date b;
Date a(2016,12,12);
Date c(2011,11,11);
b<<a<<c;
return 0;
}
看上述例子,为什么要返回this指针?原因很简单,这样我们像std命名空间的cout<<一样可以连续的使用,具体地话可以参见我之前转载的一片文章,记叙iostream中的库和stdio中标准输入输出的不同。
然后是友元函数的写法
- #include<iostream>
- using namespace std;
- class Date{
- public:
- Date(){
- }
- Date(int y,int m,int d){
- year=y;
- month=m;
- day=d;
- }
- friend ostream& operator<<(ostream &os,const Date &dt);
- private:
- int year,month,day;
- };
- ostream& operator <<(ostream& os,const Date& d)
- {
- const char sep=‘\t’;
- os<<”year:”<<d.year<<sep<<“month:”<<d.month<<sep<<“day:”<<d.day<<endl;
- return os;
- }
- int main(){
- Date a(2016,12,12);
- cout<<a;
- return 0;
- }
#include<iostream>
using namespace std;
class Date{
public:
Date(){
}
Date(int y,int m,int d){
year=y;
month=m;
day=d;
}
friend ostream& operator<<(ostream &os,const Date &dt);
private:
int year,month,day;
};
ostream& operator <<(ostream& os,const Date& d)
{
const char sep='\t';
os<<"year:"<<d.year<<sep<<"month:"<<d.month<<sep<<"day:"<<d.day<<endl;
return os;
}
int main(){
Date a(2016,12,12);
cout<<a;
return 0;
}
对于上述的问题,显然用友元的处理方式更加地科学,因为并没有必要为了使用重载后的运算符而提前实例化一个对象,在一些相关的运算符重载的问题上,最后我们应该选取何种方式来重载运算符呢?这个应该视具体情况和具体运算符而定。