C++重载>>运算符读取文件中Address对象仅输出1个的问题求助
问题背景
需要从Address.dat文件中逐个提取Address对象,但现有代码只输出第一个对象,且使用while(!file.eof())会触发无限循环。Address.dat的数据格式如下:
Hope St
67
Clarence
0917
Nelson Mandela Drive
643
Pretoria
0181
Albert St
91
Pretoria
0181
Church St
14
Wellington
6734
Main St
907
Soweto
0912
Bushbuck St
89
Polokwane
3452
原代码存在两个核心问题:
错误原因
混合输入操作的换行符残留:
重载的operator>>中,先用getline读取街道名称,再用>>读取门牌号、城市和邮编。但>>操作会在读取完数据后留下换行符在输入流中,下一次调用getline时会直接读取这个空的换行符,导致街道名称为空,后续读取门牌号时失败,输入流进入错误状态,循环终止。循环条件逻辑错误:
原代码用while(file)作为循环条件,即使读取操作失败(比如流已到末尾),仍会执行一次cout << Emp_1,而正确的做法是将读取操作直接作为循环条件,确保只有读取成功时才执行输出。
另外,原代码遗漏了<string>和<limits>头文件,可能导致编译错误或未定义行为。
修复方案
修正
operator>>的实现:
在读取完邮编后,调用ignore函数跳过输入流中剩余的换行符,避免影响下一次getline的读取。需要包含<limits>头文件来使用numeric_limits。调整循环条件:
将file >> Emp_1直接放入while循环条件中,这样只有当读取成功时才进入循环体执行输出。补充必要的头文件:
添加<string>用于字符串操作,添加<limits>用于输入流的忽略操作。
修正后的完整代码
#include <iostream> #include <fstream> #include <string> #include <limits> // 用于numeric_limits using namespace std; class Address{ public: Address(); void setStreetName(string strName); string getStreetName(); void setStreetNr(int strNr); int getStreetNr(); void setCity(string City); string getCity(); void setPostalCode(string postalCd); string getPostalCode(); friend istream &operator>>( istream &input, Address &A ); friend ostream &operator<<( ostream &output, const Address &B ); private: string streetName; int streetNr; string city; string postalCode; }; int main(){ // 读取Address.dat文件到对象 ifstream file("Address.dat"); if (!file.is_open()) { // 增加文件打开失败的判断 cerr << "无法打开文件Address.dat" << endl; return 1; } Address Emp_1; // 将读取操作放在循环条件中,读取成功才执行输出 while (file >> Emp_1) { cout << Emp_1 << endl; } file.close(); return 0; } Address::Address(){ streetName = ""; streetNr = 0; city = ""; postalCode = "0000"; } void Address::setStreetName(string strName){ streetName = strName; } string Address::getStreetName(){ return streetName; } void Address::setStreetNr(int strNr){ streetNr = strNr; } int Address::getStreetNr(){ return streetNr; } void Address::setCity(string City){ city = City; } string Address::getCity(){ return city; } void Address::setPostalCode(string postalCd){ postalCode = postalCd; } string Address::getPostalCode(){ return postalCode; } istream &operator>>( istream &input, Address &A ){ getline(input, A.streetName); // 处理可能的空行(比如文件开头或之前操作残留的换行) if (A.streetName.empty() && !input.eof()) { getline(input, A.streetName); } input >> A.streetNr >> A.city >> A.postalCode; // 跳过当前行剩余的字符,直到换行符,避免影响下一次getline input.ignore(numeric_limits<streamsize>::max(), '\n'); return input; } ostream &operator<<( ostream &output, const Address &B ){ output << B.streetName << '\n' << B.streetNr << '\n' << B.city << '\n' << B.postalCode << '\n'; return output; }
额外说明
- 添加了文件打开失败的判断,增强代码健壮性。
- 在
operator>>中增加了对空街道名称的处理,避免因输入流中的残留换行导致第一次读取失败(比如如果文件开头有空白行的情况)。
内容的提问来源于stack exchange,提问作者Ndikhokhele

