如何在BillRecord::ReadCustDetails中读取文件完整地址与负值到私有成员
解决
BillRecord::ReadCustDetails读取文件内容异常的问题 你遇到的核心问题是混合使用>>和getline导致的输入流位置错乱,以及多字段地址的读取逻辑错误,还有变量对应关系的小疏漏。我来一步步帮你修正:
问题分析
>>与getline的冲突:当你用fin >> Supplier读取供应商名称后,输入流的指针会停在Supplier后面的空白字符(空格/换行)上。此时直接调用getline(fin, Name)会读取这个空白到换行之间的空内容,导致后续所有读取都错位。- 地址读取逻辑错误:地址是由多个单词组成的(比如
24 Dingo St Exeter SA),不能直接用getline一次性读取,因为它后面紧跟着数值类型的账单金额,需要精准识别地址的结束位置。 - 变量对应错误:你的类定义里没有
AccountBalance这个私有成员,但代码里却尝试读取它,这应该是笔误,对应文件里的-0.018应该是BillAmount。
修正后的代码
#include <limits> // 用于处理流的空白跳过 #include <cstdlib> // 用于数值转换判断 // 补全类定义(修正变量对应问题) class BillRecord { public: BillRecord() = default; virtual void ReadCustDetails(std::ifstream &fin); private: enum class BillType { Phone, Gas, Elect }; // 假设的账单类型枚举,可根据实际调整 BillType BType; std::string Supplier; std::string Name, Address; double BillAmount; int DaysSinceLastReading; }; void BillRecord::ReadCustDetails(std::ifstream &fin) { // 1. 读取供应商名称 fin >> Supplier; // 跳过Supplier后残留的所有空白字符,解决>>和后续读取的冲突 fin >> std::ws; // 2. 读取客户姓名(示例中为两个单词,如George Carter) std::string firstName, lastName; fin >> firstName >> lastName; Name = firstName + " " + lastName; fin >> std::ws; // 3. 读取地址:读取所有非数值的单词,直到遇到第一个可转换为double的数值 std::string token; Address.clear(); while (fin >> token) { char* endPtr; // 尝试将token转换为double,判断是否为账单金额 double tempAmount = std::strtod(token.c_str(), &endPtr); // 如果转换成功(endPtr指向字符串末尾),说明这是BillAmount,将token放回流中 if (*endPtr == '\0') { fin.seekg(-static_cast<int>(token.size()) - 1, std::ios_base::cur); break; } // 否则将token拼接到地址中 if (!Address.empty()) { Address += " "; } Address += token; } // 4. 读取账单金额和上次读数间隔天数 fin >> BillAmount; fin >> DaysSinceLastReading; // 测试输出 std::cout << Supplier << std::endl; std::cout << Name << std::endl; std::cout << Address << std::endl; std::cout << BillAmount << std::endl; std::cout << DaysSinceLastReading << std::endl; }
关键修正点说明
- 解决流位置错乱:用
fin >> std::ws跳过>>读取后残留的空白字符,确保后续读取的是有效内容。 - 地址精准读取:通过尝试转换每个token为数值,自动判断地址的结束位置,完美适配多单词地址的场景。
- 变量对应修正:移除了不存在的
AccountBalance,将文件中的-0.018对应到类的BillAmount成员。
如果你的客户姓名可能包含更多单词(比如中间名),可以调整姓名的读取逻辑,比如用类似地址的方式读取,直到遇到数字开头的地址字段,不过根据你提供的示例,当前的姓名读取逻辑已经足够。
内容的提问来源于stack exchange,提问作者muzzi
相关产品推荐
相关产品推荐

