Question

For a user defined class I have overloaded << operator in the following way for 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;
}

How to overload >> operator equivalently for cin

Était-ce utile?

La solution

this should work:

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

Autres conseils

That's going to be hard. Since you don't know what the input is, you don't know if it's an integer or a floating point value.

What you can do is to read input as a string, and use e.g. std::stoi to convert it to an integer. If it converts the complete string then you have the second form and should read another integer. Otherwise you have a floating point value and then use e.g. std::stod to convert the string to a floating point value.

As an alternative, try reading as a floating point value with the normal input operator, and if that fails then clear the flags and read two integers.


Note, if you perform arithmetic on obj_.somefloat then it might not be exactly zero, so your condition will fail.

Right now, the way you are doing it now makes it hard to know what to expect when you read the content stream of such an object. i.e. should you read a float, an int, or a string ?

Assuming you can change the output operator, there are two approaches you can take:

Remove conditional logic altogether:

The best way to approach this in my opinion would be to rewrite your output operator as:

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

Then, you can write your input operator as:

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

(Of course, you should also add error-handling between reads)

Serialize conditional logic:

You can save the 'format' of your object as an explicit parameter. This is basically what's done in most document serialization schemes that support versioning.

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

Output operator then becomes:

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

Input operator:

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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top