Определение пользовательских манипуляторов

 

Порядок создания пользовательского манипулятора с параметрами, например для вывода, следующий:

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);