Reputation: 3272
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
Upvotes: 1
Views: 387
Reputation: 406
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;
}
Upvotes: 1
Reputation: 5118
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;
}
Upvotes: 1
Reputation: 409404
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.
Upvotes: 1