C++中结合getline、stringstream与多类重载流运算符的天气数据读取问题
Hey there! Let's work through this weather data handling problem together—sounds like you've got a solid class structure planned, so let's focus on making the stream operators work smoothly and nail those unit tests.
1. Implementing Stream Operators for Date/Time/WeatherData
First, let's tackle the core parsing logic. Since you're using separate Date and Time classes, we'll need to overload the >> extraction operator for each, then tie them together in WeatherData.
Date Class Example
You'll need to parse the DD/MM/YYYY format. Make sure to declare the operator as a friend if it needs access to private members:
#include <iostream> #include <string> class Date { private: int day, month, year; public: // Getters for unit testing int getDay() const { return day; } int getMonth() const { return month; } int getYear() const { return year; } friend std::istream& operator>>(std::istream& is, Date& date); }; std::istream& operator>>(std::istream& is, Date& date) { char slash1, slash2; // Read day / month / year, ignoring the slashes is >> date.day >> slash1 >> date.month >> slash2 >> date.year; return is; }
Time Class Example
For the HH:MM format, similar approach:
class Time { private: int hour, minute; public: // Getters for testing int getHour() const { return hour; } int getMinute() const { return minute; } friend std::istream& operator>>(std::istream& is, Time& time); }; std::istream& operator>>(std::istream& is, Time& time) { char colon; is >> time.hour >> colon >> time.minute; return is; }
WeatherData Class with Combined Parsing
Now, the WeatherData class will use the above operators, plus parse all the numeric fields. Don't forget to handle the commas separating each data point!
#include <vector> class WeatherData { private: Date date; Time time; double temp; int windDir; double windSpeed; int rain; double pressure; double pressureSeaLevel; double pressureStation; int cloudCover; double humidity; int visibility; int solarRadiation; double tempFeelsLike; double tempMax; double tempMin; public: // Getters for all fields to enable unit testing Date getDate() const { return date; } Time getTime() const { return time; } double getTemp() const { return temp; } // ... add getters for all other fields ... friend std::istream& operator>>(std::istream& is, WeatherData& data); }; std::istream& operator>>(std::istream& is, WeatherData& data) { char comma; // First parse date and time (they're in the same token: "31/03/2016 9:00") is >> data.date >> data.time; // Now skip the comma after the datetime, then parse each numeric field is >> comma >> data.temp; is >> comma >> data.windDir; is >> comma >> data.windSpeed; is >> comma >> data.rain; is >> comma >> data.pressure; is >> comma >> data.pressureSeaLevel; is >> comma >> data.pressureStation; is >> comma >> data.cloudCover; is >> comma >> data.humidity; is >> comma >> data.visibility; is >> comma >> data.solarRadiation; is >> comma >> data.tempFeelsLike; is >> comma >> data.tempMax; is >> comma >> data.tempMin; return is; }
2. Unit Testing Tips & Examples
Unit testing is all about verifying each component works as expected, then testing the whole system. Here's how to structure your tests:
Test Individual Classes First
Start small—validate that Date and Time parse correctly before moving to WeatherData:
#include <sstream> #include <cassert> void testDateParsing() { std::istringstream input("31/03/2016"); Date d; input >> d; assert(d.getDay() == 31); assert(d.getMonth() == 3); assert(d.getYear() == 2016); } void testTimeParsing() { std::istringstream input("9:00"); Time t; input >> t; assert(t.getHour() == 9); assert(t.getMinute() == 0); }
Test Full WeatherData Parsing
Use your sample data to test the complete flow:
void testWeatherDataParsing() { std::istringstream input("31/03/2016 9:00,14.6,175,17,0,1013.4,1016.9,1017,0,68.2,6,512,22.7,24.1,25.5"); WeatherData data; input >> data; // Verify date Date d = data.getDate(); assert(d.getDay() == 31); assert(d.getMonth() == 3); assert(d.getYear() == 2016); // Verify time Time t = data.getTime(); assert(t.getHour() == 9); assert(t.getMinute() == 0); // Verify numeric fields assert(data.getTemp() == 14.6); assert(data.getWindDir() == 175); assert(data.getWindSpeed() == 17); // ... add assertions for all remaining fields ... } int main() { testDateParsing(); testTimeParsing(); testWeatherDataParsing(); std::cout << "All tests passed!" << std::endl; return 0; }
3. Common Pitfalls to Watch For
- Comma Handling: The
>>operator skips whitespace but not commas—make sure you explicitly read and discard commas between fields, otherwise parsing will fail. - Data Type Mismatches: Double-check that your class members match the data types in the file (e.g., temperatures are
double, wind direction isint). - Friend Declarations: If your stream operators need access to private class members, don't forget to declare them as friends—otherwise you'll get compilation errors.
- Edge Cases: If your assignment requires it, test edge cases like leap days, 24-hour time (e.g.,
23:59), or missing/invalid data points (though this might be beyond basic unit testing).
内容的提问来源于stack exchange,提问作者Jason Collier

