Бьерн Страуструп. Язык программирования С++ Второе дополненное издание



Pdf көрінісі
бет199/256
Дата11.07.2022
өлшемі2,87 Mb.
#37591
1   ...   195   196   197   198   199   200   201   202   ...   256
10.5.2 Строковые потоки 
Как было показано, поток может быть привязан к файлу, т.е. массиву символов, хранящемуся не в 
основной памяти, а, например, на диске. Точно так же поток можно привязать к массиву символов в 


Бьерн Страуструп.
Язык программирования С++ 
 
278 
основной памяти. Например, можно воспользоваться выходным строковым потоком ostrstream для 
форматирования сообщений, не подлежащих немедленной печати: 
char* p = new char[message_size]; 
ostrstream ost(p,message_size); 
do_something(arguments,ost); 
display(p); 
С помощью стандартных операций вывода функция do_something может писать в поток ost, передавать 
ost подчиняющимся ей функциям и т.п. Контроль переполнения не нужен, поскольку ost знает свой 
размер и при заполнении перейдет в состояние, определяемое fail(). Затем функция display может 
послать сообщение в "настоящий" выходной поток. Такой прием наиболее подходит в тех случаях, 
когда окончательная операция вывода предназначена для записи на более сложное устройство, чем 
традиционное, ориентированное на последовательность строк, выводное устройство. Например, текст 
из ost может быть помещен в фиксированную область на экране. 
Аналогично, istrstream является вводным строковым потоком, читающим из последовательности 
символов, заканчивающейся нулем: 
void word_per_line(char v[], int sz) 
/* 
печатать "v" размером "sz" по одному слову в строке 
*/ 

istrstream ist(v,sz); // 
создать istream для v 
char b2[MAX]; // длиннее самого длинного слова 
while (ist>>b2) cout <
Завершающий нуль считается концом файла. 
Строковые потоки описаны в файле 
10.5.3 Буферизация 
Все операции ввода-вывода были определены без всякой связи с типом файла, но нельзя одинаково 
работать со всеми устройствами без учета алгоритма буферизации. Очевидно, что потоку ostream, 
привязанному к строке символов, нужен не такой буфер, как ostream, привязанному к файлу. Такие 
вопросы решаются созданием во время инициализации разных буферов для потоков разных типов. Но 
существует только один набор операций над этими типами буферов, поэтому в ostream нет функций, 
код которых учитывает различие буферов. Однако, функции, следящие за переполнением и 
обращением к пустому буферу, являются виртуальными. Это хороший пример применения виртуальных 
функций для единообразной работы с эквивалентными логически, но различно реализованными 
структурами, и они вполне справляются с требуемыми алгоритмами буферизации. Описание буфера 
потока в файле  может выглядеть следующим образом: 
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(); 
//... 


Бьерн Страуструп.
Язык программирования С++ 
 
279 
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. 


Достарыңызбен бөлісу:
1   ...   195   196   197   198   199   200   201   202   ...   256




©emirsaba.org 2024
әкімшілігінің қараңыз

    Басты бет