Advertisement
giGii

iostreams for structures

Sep 4th, 2022
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.07 KB | None | 0 0
  1. #include <string>
  2. #include <fstream>
  3. #include <ostream>
  4. #include <iostream>
  5. #include <iomanip>
  6. #include <sstream>
  7. #include <vector>
  8.  
  9. using namespace std;
  10.  
  11. // перегрузка операторов ввода-вывода
  12.  
  13. /* работу со структурами и классами можно сделать более удобной и более похожей на работу со стандартными типами;
  14. когда мы считываем целое число из консоли, или выводим его туда, мы делаем это очень удобно с помощью
  15. операторов ввода и вывода; так что же нам мешает для наших кастомных структур данных определить точно также
  16. операторы ввода и вывода */
  17.  
  18. // но обо всем по порядку; определим структуру
  19. struct Duration {
  20.     int hour;
  21.     int min;
  22. };
  23.  
  24. // логично предположить, что когда-нибудь мы будем считывать эту структуру из потока и выводить в поток
  25.  
  26. Duration ReadDuration(istream& stream) { // функция примет на вход поток, из которого мы ее читаем
  27.     int h = 0;
  28.     int m = 0;
  29.     stream >> h;
  30.     stream.ignore(1); // пропустим разделитель (формат ввода h:m)
  31.     stream >> m;
  32.  
  33.     return Duration {h, m};
  34. }
  35.  
  36. // логично определить функцию, которая будет выводить нашу структуру-интервал в поток,
  37. // в который мы хотим ее вывести; а также экземпляр класса, который мы хотим вывести
  38.  
  39. void PrintDuration(ostream& stream, const Duration& duration) {
  40.     stream << setfill('0'); // чтобы единицы от 0 до 9 выводились с заполнителем 0
  41.     const auto& [h, m] = duration;
  42.     stream << setw(2) << h << " :: " << setw(2) << m; // endl не пишем, т.к. имхо за перенос строки должен отвечать тот код, который вызывает PrintDuration
  43. }
  44.  
  45. /* void operator<<(ostream& stream, Duration duration) {
  46.     stream << setfill('0');
  47.     stream << setw(2) << duration.hour << " ::: " << setw(2) << duration.min;
  48. } */
  49.  
  50. ostream& operator<<(ostream& stream, Duration& duration) {
  51.         stream << setfill('0');
  52.         stream << setw(2) << duration.hour << " ::: " << setw(2) << duration.min;
  53.  
  54.         return stream;
  55. }
  56.  
  57. istream& operator>>(istream& stream, Duration& duration) {
  58.     stream >> duration.hour;
  59.     stream.ignore(1);
  60.     stream >> duration.min;
  61.  
  62.     return stream;
  63.  
  64. }
  65.  
  66. int main() {
  67.     /* stringstream dur("01:50"); // заведем поток, чтобы каждый раз не считывать из консоли
  68.     Duration duration1 = ReadDuration(dur);
  69.     ofstream output_file("output.txt");
  70.     PrintDuration(cout, duration1); // 01 :: 50
  71.     PrintDuration(output_file, duration1); // в файле output.txt первая строка это 01 :: 50 */
  72.  
  73.     /* но согласитесь, что каждый раз вызывать функцию PrintDuration и ReadDuration в принипе можно, но было бы
  74.     намного удобнее, если бы мы могли воспользоваться оператором ввода >> из любого потока (например, из cin) и
  75.     оператором вывода << нашего объекта в любой поток (например, в cout); что для этого нужно сделать?
  76.    
  77.     для этого в языке С++ уже все есть; попробуем определить наш оператор, пусть он возвращает void, после чего идет
  78.     ключевое слово operator и дальше мы должны написать оператор вывода в поток <<; далее идут аргументы в скобочках
  79.     первый аргумент это поток, в который мы будем делать запись, второй аргумент структура, которую нужно вывести
  80.  
  81.     получилась функция:
  82.     void operator<<(ostream& stream, Duration duration) {
  83.         stream << setfill('0');
  84.         stream << setw(2) << duration.hour << " ::: " << setw(2) << duration.min << endl;
  85.     }
  86.  
  87.     попробуем вывести структуру в поток cout */
  88.  
  89.     /* stringstream dur("01:50"); // заведем поток, чтобы каждый раз не считывать из консоли
  90.     Duration duration1 = ReadDuration(dur);
  91.     cout << duration1; // 01 ::: 50 */
  92.  
  93.     /* здорово, структура распечаталась, и мы сделали оператор вывода более удобным, и теперь мы смело можем удалить
  94.     функцию PrintDuration; однако если добавить перенос строки */
  95.  
  96.     /* cout << duration1 << endl; */
  97.    
  98.     /* получается ошибка, мы не можем записать endl в поток; попробуем вывести тривиальное что-то */
  99.  
  100.     /* cout << "hello" << " world" << endl; // hello world */
  101.  
  102.     /* тривиальное вывелось; представим этот код по-другому, при помощи глобального оператора вывода */
  103.  
  104.     /* operator<<(cout, "hello"); // первым аргументом он принимает поток, а вторым набор символов, которые надо вывести */
  105.    
  106.     /* после запуска кода у нас есть вывод: hello */
  107.  
  108.     /* при этом оператор вывода возвращает сам тот поток, в который он делал вывод; то есть результатом работы
  109.     operator<<(cout, "hello") будет поток cout; поэтому мы можем еще раз по цепочке вызвать оператор вывода,
  110.     передав результат работы первого оператора (результат работы -- поток) во второй оператор */
  111.  
  112.     /* operator<<(operator<<(cout, "hello"), " world"); // hello world */
  113.  
  114.     /* теперь мы понимаем, что на самом деле оператор вывода должен возвращать не void, а ссылку на поток!!!
  115.    
  116.     получилась функция:
  117.     ostream& operator<<(ostream& stream, Duration duration) {
  118.         stream << setfill('0');
  119.         stream << setw(2) << duration.hour << " ::: " << setw(2) << duration.min << endl;
  120.  
  121.         return stream;
  122.     } */
  123.  
  124.     /* stringstream dur("01:50"); // заведем поток, чтобы каждый раз не считывать из консоли
  125.     Duration duration1 = ReadDuration(dur);
  126.     cout << duration1 << endl; // 01 ::: 50\n
  127.     cout << duration1 << endl; // 01 ::: 50\n */
  128.  
  129.     /* теперь мы можем определить оператор ввода из потока */
  130.  
  131.     Duration duration2 = {0, 0}; // инициализируем нуевой интервал
  132.     stringstream dur("01:50"); // заведем строковый поток
  133.     dur >> duration2; // делаем считывание из потока в инициализированную переменную при помощи оператора ввода
  134.     cout << duration2 << endl; // выводим в поток вывода считанный интервал
  135.  
  136.     cin >> duration2;
  137.     cout << duration2 << endl;
  138.  
  139.     // таким образом рассмотрена перегрузка операторов ввода-вывода для наших собственных объектов
  140.     return 0;
  141.  
  142. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement