14-2 输入和输出运算符
14.2.1 重载输出运算符
参数与返回值
- 第一个形参:
ostream的引用
【ostream无法复制】 - 第二个新参:
常量引用
【避免复制对象】 - 返回:
ostream的引用
【链式使用】
Sale_data的输出运算符
ostream& operator<<(ostream &os; const Sale_data &item){
os<<item.ibsn();
return os;
}
输出运算符减少格式化操作:如本例中不要
<<endl
输出运算符不要作为成员函数
需要用作普通的非成员函数,
否则,它的左侧对象将会是类的对象,
上述例子将会变为:
Sale_data data;
data<<cout; //如果operator<<是data的成员
所以输出运算符一般声明为类的友元
14.2.2 重载输入运算符
参数与返回值
- 第一个形参:流的引用
- 第二个形参:对象的引用
- 返回值:流的引用
istream &operator>>(istream &is, const Sale_data &item){
double price; //不需要初始化,因为我们要读入price
is>>item.bookNo>>item.unites_sole>>price;
if(is) //检查输入是否成功
item.revenue = item.unites_sole*price;
else
item = Sale_data(); //输入失败:对象被赋予默认状态
return is;
}
输入函数必须预测可能的失败情况,并负责从错误中恢复,而输出函数不需要
输入时的错误
- 当流含有错误类型的数据时读取操作可能失败。例如在读取完bookNo后,输入运算符假定接下来读入的是两个数字数据,一旦输入的不是数字数据,则读取操作及后续对流的其他使用都将失败。
- 当读取操作到达文件末尾或者遇到输入流的其他错误时也会失败。
如果在发生错误前对象已经有一部分被改变,则适时地将对象置为合法状态显得异常重要。例如在这个输入运算符中,我们可能在成功读取新的bookNo后遇到错误,这意味着对象的units_sold和 revenue成员并没有改变,因此有可能会将这两个数据与一条完全不匹配的bookNo 组合在一起。
通过将对象置为合法的状态,我们能(略微)保护使用者免于受到输入错误的影响。此时的对象处于可用状态,即它的成员都是被正确定义的。而且该对象也不会产生误导性的结果,因为它的数据在本质上确实是一体的。
输入函数必须预测可能的失败情况,并负责从错误中恢复,而输出函数不需要