Мы уже сталкивались с перегрузкой операций ввода-вывода (см. п. п. 27.6.1.2.3 и 27.6.2.5.3 в [1]), когда рассматривали дружественные функции и виртуализацию внешних функций (см. листинги 3.12 и 9.12). Однако перегрузка выполнялась в простейшем виде, только для иллюстрации механизмов дружественности и виртуализации. Теперь мы реализуем более развитые операции для ввода и вывода дат с использованием форматирования и строковых потоков. Определим возможные форматы дат:
• три целых числа, разделенных точками; в начале — день, например 31.01.2005;
• целое число, начинающееся с года, например 20050505;
• целое число-день, строка-месяц, целое число-год, например 5-май-2005.
Соответственно, операция ввода даты должна «уметь» настраиваться на вид вводимой даты. И операция вывода тоже должна обеспечивать вывод в одном из этих трех форматов. Это легко можно сделать, написав три разных эффектора по аналогии с эффектором binary (см. листинг 14.8). Более того, так как форматирование — это «внутреннее дело» класса* даты, эти эффекторы можно объявить вложенными классами класса даты.
Однако возможны и другие пути форматирования даты. Начнем с вывода. Реализуем три манипулятора без аргументов, которые обеспечат нам ту же функциональность:
• манипулятор poi ntdate задает вывод даты в виде чисел, разделенных точками;
• манипулятор i ntdate задает вывод даты в виде целого числа;
• манипулятор stri ngdate задает вывод даты с названием месяца.
Если манипуляторы отсутствуют, то дата выводится в виде poi ntdate. Таким образом, если переменная d представляет собой дату, то вывод ее может быть таким:
cout << intdate << d: cout << pointdate << d; cout << stringdate << d;
Сразу понятно, что манипуляторы должны где-то в объекте d «оставлять следы», а операция вывода operator<< должна иметь к этой информации доступ. По аналогии со стандартным вводом-выводом манипуляторы без аргументов могут устанавливать флаг, а операция вывода этот флаг использовать. Таким образом, в класс даты нужно включить поле флагов и определить константы-флаги.
Однако есть одна тонкость: манипулятор без аргументов не получает объект-дату как параметр — аргументом такого манипулятора может быть только поток. Поэтому первое (самое простое) решение — сделать поле флагов статическим. В этом случае установка любого флага будег действовать на вывод всех объектов-дат до установки другого флага. Собственно, так работают и стандартные флаги форматирования: установка, например, флага выравнивания left действует до тех пор, пока не будет установлен другой флаг выравнивания.
Очевидно, что манипуляторы должны быть дружественными функциями для класса даты, чтобы иметь доступ к закрытому полю флагов. Таким образом, класс даты может выглядеть так, как показано в листинге 14.19.
Листинг 14.19. Класс TDate, обеспечивающий форматирование дат
class TDate { public:
typedef unsigned int fmtflags: // константы-флаги
static const fmtflags pointDate = 0x00;
static const fmtflags intDate = 0x01;
static const fmtflags stringDate = 0x02; // методы доступа к фпагам
fmtflags getflagsO const { return fmt; }
void pointdate() { fmt = pointDate; }
void intdateO { fmt = intDate; }
void stringdateO { fmt = stringDate; } // конструкторы даты
TDate():date(0) {}
TDate(unsigned long date):date(date){} TDate(unsigned int d, unsigned int m, unsigned int y) :date(y*10000+m*100+d) {}
TDate(unsigned int d, string month, unsigned int y); TDate(const TDate &d):date(d.date){} // ввод-вывод
friend istream& operator>>(istream& is, TDate &data); friend ostream& operator<<(ostream& os, const TDate &data); // манипуляторы
friend ostream& intdate (ostream &os) { fmt = intDate; return os; } friend ostream& pointdate (ostream &os) { fmt = pointDate; return os; } friend ostream& stringdate(ostream &os) { fmt = stringDate; return os; }
private:
unsigned long date; static fmtflags fmt; static const string m[12];
>:
TDate::fmtflags TDate::fmt; const string TDate::m[12] =
{ "янв","фев","мар","апр","май","июн","июп","авг","сен","окт","ноя", "дек" };
Еще несколько замечаний о классе. Дата представлена единственным полем, в котором дата хранится в виде год 10000 + месяц 100 + день.
Так как поле флагов статическое, то конструкторы его не инициализируют. Помимо манипуляторов, класс даты, естественно, предоставляет методы установки и доступа к флагам.
Если вы ищете макет ак, тогда вам сюда http://exo-voyn.com.ua/mmg/pistolety-pulemety-i-avtomvty/ak-74-detail.
Операция вывода даты может быть реализована так, как показано в листинге 14.20.
Функция, в зависимости от установленного флага, «собирает» в строковом потоке нужный вид даты, а потом выводит буфер строкового потока в поток-параметр. Все форматы даты выводятся с ведущими нулями. Нужно подключить библиотеку <iomanip>, так как используются манипуляторы с аргументами. |