Создание функций-манипуляторов, имеющих аргументы, несколько сложнее, чем манипуляторов без аргументов. Одна из причин этого заключается в том, что параметризованные манипуляторы используют классы-макросы, определенные в файле iomanip.h.
Для создания параметризованного манипулятора необходимо включить в файл заголовочный файл iomanip.h. В этом файле определено несколько макросов. Мы будем использовать два из них — OMANIP и IMANIP. Первый используется для создания манипуляторов вывода с аргументами. Второй используется для создания параметризованных манипуляторов ввода.
В общем случае, если необходимо создать манипулятор, имеющий аргументы, то следует создать две перегруженных функции-манипулятора. В одной необходимо определить два параметра. В качестве первого параметра используется ссылка на поток, а вторым является параметр, передаваемый в функцию. Вторая версия манипулятора имеет один параметр — тот, который указывается при использовании манипулятора в выражениях ввода/вывода. Эта вторая версия генерирует вызов первой версии. Общая форма манипуляторов вывода с параметрами имеет вид:
ostream& имя_манипулятора(оstream &поток, тип параметр)
{
// код
return поток;
}
OMANIP(тип) имя_манипулятора(тип параметр)
{
return OMANIP(тип)(имя_манипулятора, параметр);
}
Поскольку omanip является классом-шаблоном, то тип становится типом данных, с которыми оперирует специфический объект omanip, возвращаемый манипулятором.
Следующая программа создает параметризованный манипулятор вывода indent(), осуществляющий отступ на указанное число пробелов.
#include <iostream.h>
#include <iomanip.h>
ostream& indent(ostream &stream, int length)
{
for(int i=0; i<length; i++) cout << " ";
return stream;
}
OMANIP(int) indent(int length)
{
return OMANIP(int)(indent, length);
}
int main()
{
cout << indent (10) << "This is a test\n";
cout << indent(20) << "of the indent manipulator.\n";
cout << indent (5) << "It works!\n";
return 0;
}
Как можно видеть, манипулятор indent() перегружен в соответствии с тем, как это обсуждалось выше. Когда программа доходит до indent(10), выполняется вторая версия indent() со значением 10, переданным в параметре length. Эта версия затем исполняет первую версию с величиной 10, переданной снова в параметре length. Этот процесс повторяется всякий раз при вызове indent().
Манипуляторы для ввода данных также могут иметь параметр. В следующей программе создается манипулятор getpass(), используемый для получения пароля. Он имеет аргумент, в котором указано число попыток, предоставляемых пользователю для корректного ввода пароля.
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <stdlib.h>
char password[] = "I like C++";
char pw[80];
// ввод пароля
istream& getpass(istream &stream, int tries)
{
do
{
cout << "Enter password: ";
stream >> pw;
if(!strcmp(password, pw)) return stream;
tries--;
} while(tries>0);
cout << "All tries failed! \n";
exit(1); // пароль не введен
}
IMANIP(int) getpass(int tries)
{
return IMANIP(int)(getpass, tries);
}
int main()
{
cin >> getpass(3);
cout << "Login Complete! \n";
return 0;
}
Обратим внимание, что формат для манипуляторов ввода тот же самый, что и для манипуляторов вывода, за исключением двух моментов: используется поток ввода istream и указывается макрос IMANIP.
Подобные манипуляторы, приспособленные к конкретному использованию, могут значительно упростить инструкции ввода/вывода и улучшить читаемость кода.
7.6 Файловый ввод/вывод
Для файлового ввода/вывода можно использовать систему ввода/вывода C++. Хотя конечный результат тот же самый, но подход C++ к файловому вводу/выводу отличается в некоторых моментах от стандарта ANSI языка С для системы ввода/вывода. По этой причине обратим особое внимание на данный раздел. Для выполнения файлового ввода/вывода в программу необходимо включить заголовочный файл fstream.h. Он определяет несколько важных классов и значений.