【问题标题】:Input streaming for user defined class用户定义类的输入流
【发布时间】:2014-03-13 10:56:32
【问题描述】:

对于用户定义的类,我以以下方式为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 等效地重载&gt;&gt; 运算符

【问题讨论】:

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


    【解决方案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;
    }
    

    【讨论】:

      【解决方案2】:

      这会很难。由于你不知道输入是什么,所以你不知道它是整数还是浮点值。

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

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


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

      【讨论】:

        【解决方案3】:

        现在,您现在的操作方式使您很难知道在读取此类对象的内容流时会发生什么。即您应该读取浮点数、整数还是字符串?

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

        完全删除条件逻辑:

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

        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;
        }
        

        【讨论】:

        • if( no valid object of myObj found in stream * ) is.setstate(std::ios::failbit); 这个怎么实现,是什么意思?
        • 我不确定你在说什么。这种通用方法的问题在于,根据流类型,两个不同的对象(例如 int 和 float)很可能具有相似的表示。例如,对于二进制流,0x40000000 可能表示浮点值 2.0f,或无符号值 1073741824
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多