2014-02-14 5 views
1

Для пользовательского класса я перегружен << оператора следующим образом для 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

ответ

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

Это будет трудно. Поскольку вы не знаете, что такое вход, вы не знаете, является ли это целым числом или значением с плавающей запятой.

Что вы можете сделать, это прочитать ввод как строку и использовать, например, std::stoi, чтобы преобразовать его в целое число. Если он преобразует полную строку, то у вас есть вторая форма и она должна читать другое целое число. В противном случае вы имеете значение с плавающей запятой, а затем используйте, например, std::stod, чтобы преобразовать строку в значение с плавающей запятой.

В качестве альтернативы попробуйте читать как значение с плавающей точкой с обычным оператором ввода, а если это не удается, то clear the flags и прочитайте два целых числа.


Обратите внимание, если вы выполняете арифметику obj_.somefloat, то это может не быть точно равна нулю, поэтому ваше состояние не удастся.

1

Прямо сейчас, как вы это делаете, теперь трудно понять, чего ожидать, когда вы читаете поток контента такого объекта. т.е. если вы читаете float, 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; 
} 
+0

'если (не действительный объект myObj не найдено в потоке *) '' is.setstate (std :: ios :: failbit); 'Как реализовать это и что это значит? – eldos

+0

Я не уверен, о чем вы говорите. Проблема с этим генеалогическим подходом заключается в том, что в зависимости от типа потока два разных объекта (например, int и float) могут иметь одинаковые представления. Например, с бинарным потоком '0x40000000' может означать значение float 2.0f или значение без знака 1073741824 –

Смежные вопросы