重载操作符是个好青年,但是要吐槽的是,我们时常为了重载操作符编写许多重复的代码。这是枯燥的,但是也是必须的。你重载的越多,你的类的弹性就越大。但是,你也不能为所欲为。玩游戏总是遵守相应的规则,写重载操作符亦是如此
!
以下是要遵守的游戏规则:
- 一元操作符可以是不带参数的成员函数或带一个参数的非成员函数。
- 二元操作符可以是带一个参数的成员函数或带两个参数的非成员函数。
- operator=、operator[]、operator()、operator->只能定义为成员函数。
- operator->的返回值必须是一个指针或能使用->的对象。
- 重载 operator++ 和 operator--时带一个 int 参数表示后缀,不带参数表示前缀。
- 除 operator new 和 operator delete 外,重载的操作符参数中至少要有一个非内建数据类型。
- 重载的的操作符应尽量模拟操作符对内建类型的行为。
在看完游戏规则之后,我们就各个部分的实现和注意点进行肢解。
⒈ 输入和输出操作符的重载
对于>>和<<的重载要注意以下几个要点:
① IO操作符必须为非成员函数,如果将其定义为成员函数,那么IO操作符的操作习惯将和正常的习惯相反。多怪啊!此时,你或许会问,那我怎么调用对象中的私有成员呢?别急,我们不是有友员和友类吗?将IO操作符重载函数定义成类的友员函数,这个问题就迎刃而解了
。
② 在输入期间,我们可能会碰到错误。此时,要恢复对象为初始状态。也就是,在输入之前什么样子,我们就恢复成那个样子。
③ 这个要点是摘至《C++ primer》,我觉得挺好的。我们可以重载操作符,意味着我们自由的空间就大了。但是,我们不要忘了IO操作符的本质,不要过度的格式化,应将格式化降到最低。
在注意了几个要点之后,我们看一个完整的IO操作符的实现例子:
#include <iostream>
#include <string>
using namespace std;
class MyClass {
private:
string name;
int id;
int prefix;
int value;
public:
MyClass() { };
MyClass(string n, int a, int p, int nm):name(n), id(a), prefix(p), value(nm){} // 利用初始化列表来初始化成员对象
friend ostream &operator<<(ostream &stream, MyClass o); // 操作符被定义为非成员函数时,要将其定义为所操作类的友员
friend istream &operator>>(istream &stream, MyClass &o);
};
ostream &operator<<(ostream &stream, MyClass o)
{
stream << o.name << " ";
stream << "(" << o.id << ") ";
stream << o.prefix << "-" << o.value << "\n";
return stream;
}
istream &operator>>(istream &stream, MyClass &o)
{
cout << "Enter name: ";
stream >> o.name;
cout << "Enter id: ";
stream >> o.id;
cout << "Enter prefix: ";
stream >> o.prefix;
cout << "Enter value: ";
stream >> o.value;
cout << endl;
return stream;
}
int main()
{
MyClass a;
operator>>(cin, a); // 相当于operator>>(cin, a)
cout << a; // 相当于operator<<(cout, a)
return 0;
}