Определение пользовательских манипуляторов
Порядок создания пользовательского манипулятора с параметрами, например для вывода, следующий:
1. Определить класс (my_manip) с полями: параметры манипулятора, указатель на функцию типа
ostream& (*f)(ostream&,<параметры манипулятора>);
2. Определить конструктор этого класса (my_manip) с инициализацией полей.
3. Определить, в этом классе дружественную функцию – operator<<. Эта функция в качестве правого аргумента принимает объект класса my_manip, левого аргумента (операнда) поток ostream и возвращает поток ostream как результат выполнения функции *f. Например,
typedef far ostream&(far *PTF)(ostream&,int,int,char);
class my_man{
int w;int n;char fill;
PTF f;
public:
//конструктор
my_man(PTF F,int W,int N,char FILL):f(F),w(W),n(N),fill(FILL){}
friend ostream& operator<<(ostream&,my_man);
};
ostream& operator<<(ostream& out,my_man my)
{return my.f(out,my.w,my.n,my.fill);}
4. Определить функцию типа *f (fmanip), принимающую поток и параметры манипулятора и возвращающую поток. Эта функция собственно и выполняет форматирование. Например,
ostream& fmanip(ostream& s,int w,int n,char fill)
{s.width(w);
s.flags(ios::fixed);
s.precision(n);
s.fill(fill);
return s;}
5. Определить собственно манипулятор (wp) как функцию, принимающую параметры манипулятора и возвращающую объект my_manip, поле f которого содержит указатель на функцию fmanip. Например,
my_man wp(int w,int n,char fill)
{return my_man(fmanip,w,n,fill);}
Для создания пользовательских манипуляторов с параметрами можно использовать макросы, которые содержатся в файле <iomanip.h>:
OMANIP(int)
IMANIP(int)
IOMANIP(int)
Состояние потока.
Каждый поток имеет связанное с ним состояние. Состояния потока описываются в классе ios в виде перечисления enum.
public:
enum io_state{
goodbit, //нет ошибки 0Х00
eofbit, //конец файла 0Х01
failbit, //последняя операция не выполнилась 0Х02
badbit, //попытка использования недопустимой операции 0Х04
hardfail //фатальная ошибка 0Х08
};
Флаги, определяющие результат последней операции с объектом ios, содержатся в переменной state. Получить значение этой переменной можно с помощью функции int rdstate().
Кроме того, проверить состояние потока можно следующими функциями:
int bad(); 1, если badbit или hardfail
int eof(); 1, если eofbit
int fail(); 1, если failbit, badbit или hardfail
int good(); 1, если goodbit
Если операция >> используется для новых типов данных, то при её перегрузке необходимо предусмотреть соответствующие проверки.
Файловый ввод-вывод
Потоки для работы с файлами создаются как объекты следующих классов:
ofstream – запись в файл;
ifstream – чтение из файла;
fstream – чтение/запись.
Для создания потоков имеются следующие конструкторы:
fstream();
создает поток, не присоединяя его ни к какому файлу.
fstream(const char* name,int mode,int p=filebuf::openprot);
создает поток, присоединяет его к файлу с именем name, предварительно открыв файл, устанавливает для него режим mode и уровень защиты p. Если файл не существует, то он создается. Для mode=ios::out, если файл существует, то его размер будет усечен до нуля.
Флаги режима определены в классе ios и имеют следующие значения:
in - для чтения
out - для записи
ate - индекс потока помещен в конец файла. Чтение больше не допустимо, выводные данные записываются в конец файла;
app - поток открыт для добавления данных в конец. Независимо от seekp() данные будут записываться в конец;
trunc - усечение существующего потока до нуля;
nocreate -команда открытия потока будет завершена неудачно, если файл не существует;
noreplace -команда открытия потока будет завершена неудачно, если файл существует;
binary-поток открывается для двоичного обмена.
Если при создании потока он не присоединен к файлу, то присоединить существующий поток к файлу можно функцией
void open(const char* name,int mode,int p=filebuf::openprot);
Функция
void fstreambase::close();
сбрасывает буфер потока, отсоединяет поток от файла и закрывает файл. Эту функцию необходимо явно вызвать при изменении режима работы с потоком. Автоматически она вызывается только при завершении программы.
Таким образом, создать поток и связать его с файлом можно тремя способами:
1. Создается объект filebuf
filebuf fbuf;
Объект filebuf связывается с устройством (файлом)
fbuf.open(“имя”,ios::in);
Создается поток и связывается с filebuf
istream stream(&fbuf);
2. Создается объект fstream (ifstream, ofstream)
fstream stream;
Открывается файл, который связывается через filebuf с потоком
stream.open(“имя”,ios::in);
3. Создается объект fstream, одновременно открывается файл, который связывается с потоком
fstream stream(“имя”,ios::in);