重载输入流运算符>>用于从文件中读取对象

时间:2014-05-07 15:31:08

标签: c++ file-io operator-overloading istream

我有一个简单的课程City,其中包含idnamesizeOfPopulation和坐标xy。我有一个文本文件,如下所示:

City;1;Stockholm;300000;45;78;
City;2;Helsinky;451200;11;74;
City;3;Prague;897455;12;85;

每行代表以下内容:指标中的第一行,即城市。接下来是城市的ID,名称,人口规模,x和y。

我想阅读此文件并使用城市创建矢量。我知道,我需要重载运算符<<。

friend istream& operator >> (istream& is, City& c)
{
    // I do not know
}

之后,我将能够从for循环中的文件加载城市。你可以帮我解决一下超载运营商吗?

2 个答案:

答案 0 :(得分:1)

像这样:

#include <istream>
#include <sstream>

friend istream& operator >> (istream& is, City& c)
{
    // get whole line
    string line;
    if (!getline(is, line))
    {
        // error reporting and exit goes here...
    }

    // replace all ';' to ' '
    for (int i = 0; i < line.length(); i++)
    {
        if (line[i] == ';')
            line[i] = ' ';
    }

    // start parsing here
    istringstream iss(line);
    string tmp;
    if (iss >> tmp >> c.id >> c.name >> sizeOfPopulation >> c.x >> c.y)
    {
        // error reporting and exit goes here...
    }

    return input;
}

要在循环中阅读City个对象,您可以使用:

City c;
while (is >> c) // suppose "is" is the opened input stream
{
    // successfully read a City, stored in c
}

答案 1 :(得分:0)

在这种情况下,我会使用getline来读取该行,然后将其拆分 在';'上使用类似的内容:

std::vector<std::string>
split( std::string const& source, char separ )
{
    std::vector<std::string> results;
    std::string::const_iterator start = source.begin();
    std::string::const_iterator end = source.end();
    std::string::const_iterator next = std::find( start, end, separ );
    while ( next != end ) {
        results.push_back( std::string( start, next ) );
        start = next + 1;
        next = std::find( start, end, separ );
    }
    results.push_back( std::string( start, end ) );
}

(您可能希望将其扩展为修剪前导和尾随 空间等。)

对于字符串的字段,您只需索引到 std::vector;对于其他人,使用字符串值 初始化std::istringstream以转换它们(或 std::stoi,如果你有C ++ 11)。所以你最终会得到一些东西 像:

std::istream&
operator>>( std::istream& source, City& dest )
{
    std::string record;
    if ( std::getline( source, record ) ) {
        std::vector<std::string> fields = split( record );
        if ( fields.size() != 7 || fields[0] != "City" || fields[6] != "" ) {
            source.setstate( std::ios_base::failbit );
        } else {
            try {
                dest = City( std::stoi( vector[1] ),
                             std::vector[2],
                             std::stoi( vector[3] ),
                             Coordinates( std::stoi( vector[4] ),
                                          std::stoi( vector[5]) ) ) );
            catch ( ... ) {
                source.setstate( std::ios_base::failbit );
            }
        }
    }
    return source;
}

try ... catch的需求并不是很好,但是那个 std::stoi报告错误的方式。)