今天在做C++ Primer习题的14.11时,印象中应该挺简单的一题,结果却费了很长时间。

类定义:

typedef string Date;

class CheckoutRecord{
public:
CheckoutRecord(){book_id=-1;}
friend ostream& operator<<(ostream &os,const CheckoutRecord &obj);
friend istream& operator>>(istream &in,CheckoutRecord &obj);
private:
double book_id;
string title;
Date date_borrowed;
Date date_due;
pair<string,string> borrower;
vector<pair<string,string>*>wait_list;
};

重载输出操作符很简单:

ostream& operator<<(ostream &os,const CheckoutRecord &obj)
{
os<<"Book ID:"<<obj.book_id<<endl;
os<<"Title :"<<obj.title<<endl;
os<<"Data borrowed:"<<obj.date_borrowed<<endl;
os<<"Date due :"<<obj.date_due<<endl;
os<<"Borrower :"<<obj.borrower.first<<" "<<obj.borrower.second<<endl;
os<<"Waiters for this book:"<<endl;
for(unsigned int i=0;i<obj.wait_list.size();++i)
os<<obj.wait_list[i]->first<<" "<<obj.wait_list[i]->second<<";";
os<<endl;
return os;
}

重载输入操作符复杂一点,因为我们要考虑用户输入错误的情况:

istream& operator>>(istream &in,CheckoutRecord &obj)
{
in>>obj.book_id;
if(in){
//when you typed newline,the new line was added to the
//stream buffer, but "in>>obj.book_id" only reads the first double data and
// left '\n' character still in the input stream buffer.
in.ignore(INT_MAX,'\n');
//Title may contain spaces
std::getline(in,obj.title); in>>obj.date_borrowed>>obj.date_due>>\
obj.borrower.first>>obj.borrower.second; while(in){
pair<string,string> *waiter=new pair<string,string>;
in>>waiter->first;
if(waiter->first=="end"){
delete waiter;
break;
}
in>>waiter->second;
obj.wait_list.push_back(waiter);
}
}
else
obj=CheckoutRecord();
return in;
}

之所以费了很长时间,主要因为前面少写了一行代码:

		in.ignore(INT_MAX,'\n');
导致后面的getline得到的是空行。

为什么要加上这样一行,我在注释中已经写明了原因。以前一直以为"cin>>whatever_data"这类输入语句,碰到换行或是空白这些分隔符的时候,会在流缓冲中去除有效输入后的下一个分隔符,原来这些分隔符都还在保存在缓冲中!输入语句的行为应该是这样,只会在流中消除在它要的有效输入的前面的分隔符字符,得到想要的输入后,后面又碰到一个分隔符,说明该输入数据结束。但不对想要的输入数据后面的分隔符做任何处理

不仅是对分隔符,对于输入错误时,"cin>>.."语句在输入终止后,使输入错误的字符让保留在流缓冲区内,这是一定要用cin.ignore来清理。

8.2节中的例子:

int ival;
// read cin and test for only EOF; loop is excuted even if there are other IO failures
while(cin >> ival, !cin.eof()){
if(cin.bad()) // input stream is corrupted; bail out
throw runtime_error("IO stream corrupted!");
if(cin.fail()){
cerr << "Bad data, try again!";
cin.clear();
cin.ignore();
continue;
}
}

不仅是C++的标准IO库,C中的标准IO库也用同样的问题——如果在scanf后面直接调用getline,也会得到空行。而且,对应cin.ignore(),可用fflush(stdin)来刷新缓冲区。

那哪些输入函数会自动处理有效输入后的换行符呢?

getline和fgets这类以行为单位的输入函数,会自动将已输入行的换行符从输入缓冲中去除。

这个教训再次告诉我们,使用函数接口的时候,一定要理清它们的行为细节。有时还要弄清它们的底层实现,才能更好地理解它们的行为

最后给出main函数和测试用例:

/*
Sample Input: 1001
Miserable World
201308
201309
Simon Smith
Mike a
Kris b
Tom c
Bison d
Jumping e
end err_id
Miserable World
201308
201309
Simon Smith
Mike a
Kris b
Tom c
Bis d
Jump e
end */
int _tmain(int argc, _TCHAR* argv[])
{
CheckoutRecord record;
cin>>record;
cout<<"========================================"<<endl;
cout<<record;
}

最新文章

  1. 实现MVC自定义过滤器,自定义Area过滤器,自定义Controller,Action甚至是ViewData过滤器
  2. C#扩展方法
  3. MVVM页面跳转 技巧性标记
  4. 进击的Python【第十七章】:jQuery的基本应用
  5. 在命令行下使用perl
  6. 【笔记】jquery js获取浏览器滑动条距离顶部距离的写法
  7. Pyhton的发展历程
  8. OpenMP之求和(用section分块完成)
  9. 如何在html结构标签中使用js 变量 生成可变化的 title标题?
  10. 20145120 《Java程序设计》第6周学习总结
  11. [LCA &amp; RMQ] [NOIP2013] 货车运输
  12. Java多线程中变量的可见性
  13. C# 快速高效率复制对象另一种方式 表达式树
  14. 51Nod 1125 交换机器的最小代价
  15. HTML5支持服务器发送事件(Server-Sent Events)-单向消息传递数据推送(C#示例)
  16. Linux---基础指令(一)
  17. 学习实践之DEMO《nodejs模拟POST登陆》
  18. Oracle 分区表 收集统计信息 参数granularity
  19. CHAR 和VARCHAR的区别
  20. java中的中文字符转码技术

热门文章

  1. 关联 Android 源代码 到 Ecplise
  2. HttpClient SSL示例(转)
  3. [摘] SQLPLUS Syntax
  4. Spring Aop实例之xml配置
  5. 南京邮电大学CTF隐写术部分Writeup
  6. 去除C/C++程序代码中的注释
  7. 1176: [Balkan2007]Mokia - BZOJ
  8. jquery 数组和字典
  9. Windows2003/2008/2008 R2下易语言点支持库配置就退出的问题
  10. 跟随屏幕滚动层、遮罩层、获取Div相对定位、整个屏幕、html文档的jquery基本操作