在c++中类的私有成员是不能被直接访问的,需要通过类中提供的成员函数简介的操作这些数据。同时C++ 能够使用流提取运算符 >> 和流插入运算符 << 来输入和输出内置的数据类型。可以重载流提取运算符和流插入运算符来操作对象等用户自定义的数据类型。
但是如果直接在类内部直接重载输入、输出流运算符,那么在使用时只能通过Obj>>cin //相当于 Obj.operator>>(cin)
或是Obj<<cout//相当于 Obj.operator<<(cout) 的方式调用,但这种方式不太习惯于我们平时的操作方式,所以很多人通过用友元去实现此类重载。
用友元的方式有利有弊,通常它可以在较为频繁访问类私有成员时代替调用函数成员这一步骤,节省一些不必要的调用,减轻代码量提高效率,但同时它也破坏了内的封装性,不安全。
所以,我这里没有采取友元的方式去重载,而是通过在类外新实现了一种方法,在函数内部实现这一过程,而留给用户的接口任然是以前得读写习惯,代码如下:
class Date
{
private:
int year;
int month;
int day;
public:
Date() {}
~Date() {}
istream & operator>>(istream &in)
{
in>>year>>month>>day;
return in;
}
ostream & operator<<(ostream &out) const
{
out<<year<<" "<<month<<" "<<day<<" ";
return out;
}
};
istream& operator>>(istream& in, Date& date)
{
// date.operator>>(in); 调用date的成员函数
date >> in;
return in;
}
ostream& operator<<(ostream& out, const Date& date)
{
// date.operator<<(out); 调用date的成员函数
date << out;
return out;
}
分析:
在类的内部重载输出流与输入流运算符,他们的调用逻辑是 对象.调用函数(输出/输出流) 。通过对象调用自身的函数,把输入流或输出流当做参数调用。因此,我们在进行输入或输出的操作时不得不使用如下的方式:
int main()
{
Date date;
date.operator>>(cin); // 输入
date.operator<<(cout); // 输出
return 0;
}
这样的语法很不直观,也不符合我们的代码编写逻辑,因此我们可以考虑增加一个中间层来解决。具体的,我们可以编写一个函数,让此函数帮我们调用输入输出。这个中间层函数无疑是符合我们书写习惯的语法逻辑,而我们通过该函数的调用方式便可简介的完成输入输出操作。
int main()
{
Date date;
cin >> date; // 输入
cout << date; // 输出
return 0;
}
此外,为了提高函数的调用效率,我们可以将此中间层函数设计成内联的(inline)。
扩展:
类似的还有 operator+、operator- 等函数重载方式,在类中重载这些函数后,只能通过类对象在前,参数在后的调用方式。例如:
class Int
{
private:
int mval;
public:
Int(int v = 0) :mval(v) {}
// 重载 operator+
Int operator+(const Int& rhs) const
{
return Int(mval + rhs.mval);
}
Int operator+(const int val) const
{
return Int(mval + val);
}
};
Int operator+(const int val, const Int& rhs)
{
return rhs + val;
}
int main()
{
Int it1(10);
Int it2(20);
int ix = 30;
Int re1 = it1 + it2; // 对象+对象
Int re2 = it1 + ix; // 对象+整数
Int re3 = ix + it1; // 整数+对象
return 0;
}
我们在类中重载了对象之间的 operator+,对象与整数之间的 operator+,在类外通过一个中间函数实现了 整数与对象之间的 operator+ 。