Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КРАТКИЙ ОБЗОР С.doc
Скачиваний:
1
Добавлен:
26.10.2018
Размер:
2.11 Mб
Скачать

10.5.3 Буферизация

Все операции ввода-вывода были определены без всякой связи с типом файла, но нельзя одинаково работать со всеми устройствами без учета алгоритма буферизации. Очевидно, что потоку ostream, привязанному к строке символов, нужен не такой буфер, как ostream, привязанному к файлу. Такие вопросы решаются созданием во время инициализации разных буферов для потоков разных типов. Но существует только один набор операций над этими типами буферов, поэтому в ostream нет функций, код которых учитывает различие буферов. Однако, функции, следящие за переполнением и обращением к пустому буферу, являются виртуальными. Это хороший пример применения виртуальных функций для единообразной работы с эквивалентными логически, но различно реализованными структурами, и они вполне справляются с требуемыми алгоритмами буферизации. Описание буфера потока в файле <iostream.h> может выглядеть следующим образом:       class streambuf { // управление буфером потока       protected:       char* base; // начало буфера       char* pptr; // следующий свободный байт       char* gptr; // следующий заполненный байт       char* eptr; // один из указателей на конец буфера       char alloc; // буфер, размещенный с помощью "new"       //...       // Опустошить буфер:       // Вернуть EOF при ошибке, 0 - удача       virtual int overflow(int c = EOF);       // Заполнить буфер:       // Вернуть EOF в случае ошибки или конца входного потока,       // иначе вернуть очередной символ       virtual int underflow();       //...       public:       streambuf();       streambuf(char* p, int l);       virtual ~streambuf();       int snextc() // получить очередной символ       {       return (++gptr==pptr) ? underflow() : *gptr&0377;       }       int allocate(); // отвести память под буфер       //...       }; Подробности реализации класса streambuf приведены здесь только для полноты представления. Не предполагается, что есть общедоступные реализации, использующие именно эти имена. Обратите внимание на определенные здесь указатели, управляющие буфером; с их помощью простые посимвольные операции с потоком можно определить максимально эффективно (и причем однократно) как функции-подстановки. Только функции overflow() и underflow() требует своей реализации для каждого алгоритма буферизации, например:       class filebuf : public streambuf {       protected:       int fd; // дескриптор файла       char opened; // признак открытия файла       public:       filebuf() { opened = 0; }       filebuf(int nfd, char* p, int l)       : streambuf(p,l) { /* ... */ }       ~filebuf() { close(); }       int overflow(int c=EOF);       int underflow();       filebuf* open(char *name, ios::open_mode om);       int close() { /* ... */ }       //...       };       int filebuf::underflow() // заполнить буфер из "fd"       {       if (!opened || allocate()==EOF) return EOF;       int count = read(fd, base, eptr-base);       if (count < 1) return EOF;       gptr = base;       pptr = base + count;       return *gptr & 0377; // &0377 предотвращает размножение знака       } За дальнейшими подробностями обратитесь к руководству по реализации класса streambuf.