用户定义类的输入流

时间:2014-02-14 07:29:46

标签: c++ operator-overloading iostream cin istream

对于用户定义的类,我按以下方式为<<重载cout运算符

ostream& operator<<(ostream& os, const myObject& obj_)
{
    if (obj_.somefloat != 0)
        os << "(" << obj_.somefloat << ")";
    else if ( obj_.oneint != 0 && obj_.twoint != 0)
        os << "(" << obj_.oneint << "#" << obj_.twoint << ")";
    else    
        os << "Empty Object";
    return os;
}

如何为>>

等效地重载cin运算符

3 个答案:

答案 0 :(得分:1)

那将是艰难的。由于您不知道输入是什么,因此您不知道它是整数还是浮点值。

您可以做的是将输入作为字符串读取,并使用例如std::stoi将其转换为整数。如果它转换完整的字符串,那么你有第二种形式,应该读取另一个整数。否则你有一个浮点值,然后使用例如std::stod将字符串转换为浮点值。

作为替代方法,尝试使用普通输入操作符作为浮点值读取,如果失败则读取clear the flags并读取两个整数。


注意,如果您对obj_.somefloat执行算术,那么它可能不会完全为零,因此您的条件将会失败。

答案 1 :(得分:1)

现在,您现在这样做的方式让您很难知道在阅读此类对象的内容流时会发生什么。即你应该读一个浮点数,一个int或一个字符串?

假设您可以更改输出运算符,可以采用两种方法:

完全删除条件逻辑:

在我看来,解决这个问题的最佳方法是将输出运算符重写为:

ostream& operator<<(ostream& os, const myObject& obj)
{
    os << '(' << obj.somefloat << ')'
     << '(' << obj.oneint
     << '#' << obj.twoint << ')';
    return os;
}

然后,您可以将输入运算符编写为:

istream& operator>>(istream& is, myObject& obj)
{
    char discard = 0;
    is >> discard;
    is >> obj.somefloat;
    is >> discard >> discard;
    is >> obj.oneint >> discard;
    is >> obj.twoint >> discard;
    return is;
}

(当然,你还应该在读取之间添加错误处理)

序列化条件逻辑:

您可以将对象的“格式”保存为显式参数。这基本上是在大多数支持版本控制的文档序列化方案中所做的。

enum SerializationMode {
    EMPTY = 0,
    FLOAT,
    INT_PAIR
};

输出操作符然后变为:

ostream& operator<<(ostream& os, const myObject& obj)
{
    SerializationMode mode = EMPTY;
    if (obj.somefloat != 0)
        mode = FLOAT;
    else if ( obj.oneint != 0 && obj.twoint != 0)
        mode = INT_PAIR;

    os << mode << '#';
    if (FLOAT == mode)
        os << "(" << obj.somefloat << ")";
    else if (INT_PAIR == mode)
        os << "(" << obj.oneint << "#" << obj.twoint << ")";

    return os;
}

输入操作员:

istream& operator>>(istream& is, myObject& obj)
{
    char discard = 0;
    unsigned uMode = 0;
    is >> uMode >> discard;
    auto mode = static_cast<SerializationMode>(uMode);

    switch(mode) {
         default: break;
         case FLOAT: {
             is >> discard >> obj.somefloat >> discard;
             break;
         }
         case INT_PAIR: {
             is >> discard >> obj.oneint >> discard;
             is >> obj.twoint >> discard;
             break;
         }
    }
    return is;
}

答案 2 :(得分:1)

这应该有效:

std::istream& operator>>( std::istream& in, myObject& obj_ )
{
    char c;
    if( in >> c )
    {
        if( c == '(' )
        {
            float f;
            if( in >> f >> c ) // f reads also an int
            {
                if( c == ')' )  // single float format
                {
                    if( f != 0.0 )
                        obj_.somefloat = f;
                    else
                        in.setstate( std::ios_base::failbit );
                }
                else if( c == '#' ) // two int format
                {
                    if( float(int(f)) != f  )
                        in.setstate( std::ios_base::failbit );
                    else
                    {
                        obj_.somefloat = 0;
                        obj_.oneint = int(f);
                        if( in >> obj_.twoint >> c && (c != ')' || (obj_.oneint == 0 && obj_.twoint == 0) ) )
                            in.setstate( std::ios_base::failbit );
                    }
                }
                else
                    in.setstate( std::ios_base::failbit );
            }
        }
        else if( c == 'E' ) // "Empty Object"
        {
            const char* txt="Empty Object";
            ++txt; // 'E' is already read
            for( ; *txt != 0 && in.get() == *txt && in; ++txt )
                ;
            if( *txt == char(0) )
            {
                obj_.somefloat = 0;
                obj_.oneint = 0;
                obj_.twoint = 0;
            }
            else
                in.setstate( std::ios_base::failbit );
        }
        else
            in.setstate( std::ios_base::failbit );
    }
    return in;
}