Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lutsik_Yu_A_Obektno_orientir_programmir_na_yaz.pdf
Скачиваний:
63
Добавлен:
11.05.2015
Размер:
4.33 Mб
Скачать

ция get.

. . .

while(сin.get(с)) cout.put(c);

. . .

При третьем варианте функция get() принимает три параметра: указа- тель на символьный массив (строку), максимальное число символов и ограни- читель ввода (по умолчанию '\n'). Ввод прекращается, когда считано число сим- волов на один меньшее максимального или считан символ-ограничитель. При этом во вводимую строку добавляется нуль-символ. Символ-ограничитель из входного потока не удаляется, это при повторном вызове функции get приведет

к формированию пустой строки.

 

 

 

Р

 

сhar s[30];

 

 

 

У

 

. . .

 

 

 

Г

И

 

сin.get(s,20))

// аналогично cin.get(s,20, '\n')

 

cout<<s<<endl;

 

 

 

 

 

 

 

. . .

 

 

 

 

 

 

 

 

Функция isteram::getline() действует аналогично функции get() с тремя па-

 

 

 

 

а

 

 

 

раметрами с тем отличием, что символ-огр ничитель удаляется из входного по-

тока.

 

 

 

к

Б

 

 

 

 

Ниже коротко рассмотрены другие функции-компоненты класса istream.

 

7.2. Состояние потока

 

 

 

 

 

 

 

 

т

 

 

 

 

 

 

Потоки istream или ostream имеют связанное с ними состояние. В классе

ios, базовом для классов istreamеи ostream, имеется несколько public-функций,

позволяющих проверя ь и ус анавливать состояние потока:

 

 

inline int

ios::bad() const { return state & badbit; }

 

 

 

и

 

 

 

 

 

 

 

inline int

ios::eof() const { return state & eofbit; }

 

 

 

 

inline int

ios::оfail() const { return state & (badbit | failbit); }

 

 

inline int

ios::good() const { return state == 0; }

 

 

 

 

б

 

 

 

 

 

 

 

 

Состояние потока фиксируется в элементах перечисления, объявленного в

и

 

 

 

 

 

 

 

классе ios:л

 

 

 

 

 

 

Б

public:

 

 

 

 

 

 

 

enum io_state {

goodbit = 0x00,

 

 

 

 

 

 

eofbit

= 0x01,

 

 

 

 

 

 

failbit

= 0x02,

 

 

 

 

 

 

badbit

= 0x04 };

 

 

 

 

 

Состояние потока принимает значение goodbit или eofbit, если последняя

операция ввода прошла успешно. Если состояние goodbit, то следующая опера- ция ввода может пройти успешно. Состояние потока принимает значение eofbit, если при вводе встречен признак конца файла. Отличие между состояниями failbit и badbit очень незначительно. В состоянии failbit предполагается, что в потоке происходит ошибка форматирования, но поток не испорчен и символы в

149

потоке не потеряны. В состоянии badbit может быть все что угодно.

Кроме отмеченных выше функций в классе ios есть еще несколько функ- ций, позволяющих прочитать (rdstate) и очистить (clear) состояние потока:

inline int ios::rdstate() const { return state; }

inline void ios::clear(int _i=0){ lock(); state = _i; unlock(); }

Так, если было установлено состояние ошибки, то попытка выполнить ввод/вывод будет игнорироваться до тех пор, пока не будет устранена причина ошибки и биты ошибки не будут сброшены функцией clear().

#include <iostream>

 

 

 

 

 

 

Р

using namespace std;

 

 

 

 

 

 

int main()

 

 

 

 

 

 

 

 

{ int i, flags;

 

 

 

 

 

У

char c;

 

 

 

 

 

do{ cin >> i;

 

 

 

 

 

 

И

flags=cin.rdstate(); // чтение состояния потока cin

 

 

if(flags & ios::failbit)

 

Б

 

 

 

 

}

 

 

 

 

 

 

 

 

 

{ cout << "error in stream"<< endl;

 

 

 

 

 

cin.clear(0);

// сброс всех состояний потокаГ

 

 

cin>>c;

 

 

а

 

 

 

 

 

// удаление не int зн чения из потока

 

 

else cout << i<<endl;

к

 

 

 

 

 

 

 

 

 

 

 

} while(flags);

 

// пока ошиб а во входном потоке

 

 

 

 

return 0;

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

В приведенном примере функцияеcin.clear(0) выполняет сброс всех уста-

 

 

 

 

о

 

 

 

только badbit, то

новленных бит ошибки. Если ребуе ся сбросить, например,

 

 

 

при

 

 

 

 

 

 

clear(ios::badbit). На примере ниже показано, что состояние потока может быть

проанализировано также

рабтес файлами.

 

 

 

 

 

 

 

л

 

 

 

 

 

 

 

#include <fstream>

 

 

 

 

 

 

 

 

б

 

 

 

 

 

 

 

 

#include <iostream>

 

 

 

 

 

 

 

using namespace std;

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

 

int main()

 

 

 

 

 

 

 

 

 

{ ifstream in("file");

 

 

 

 

 

 

 

Б

 

 

 

 

 

 

 

 

 

 

int state;

 

 

 

 

 

 

 

 

 

char ss[10];

 

 

 

 

 

 

 

 

while(1)

 

 

 

 

 

 

 

 

 

{ state=in.rdstate();

// чтение состояния потока in (файла)

 

if (state)

 

 

// ошибка в потоке

 

 

 

 

 

{ if(state&ios::badbit) cout<<"ошибка открытия файла"<<endl;

else if(state&ios::eofbit) cout<<"в файле больше нет данных"<<endl; return 0;

}

150

else in >> ss;

}

}

Необходимо также отметить, что в классе ios выполнена перегрузка опе- рации ! :

inline int ios::operator!() const { return state&(badbit|failbit); }

то есть операция ! возвращает ненулевое значение в случае установки од- ного из бит badbit или failbit, иначе нулевое значение, например:

if(!cin) cout << ”ошибка потока cin”<<endl;

// проверка состояния

else cin>>i;

// входного потока

7.3. Строковые потоки

 

 

 

 

 

Особой разновидностью потоков являются строковые потокиР, представ-

ленные классом strstream:

 

 

 

У

 

 

Г

И

class strstream : public iostream

{ public:

 

 

 

strstream();

 

 

 

strstream(char *s, streamsize n,

 

 

 

а

 

 

ios_base::openmode=ios

base::in | ios_base::out);

strstreambuf *rdbuf() const;

 

Б

 

 

 

к

 

 

 

void freeze(bool frz=true);

 

 

 

 

char *str();

 

 

 

 

 

streamsize pcount() const;

};

 

 

Важное свойс во классаеstrstream состоит в том, что в нем автоматически

о

 

выделяется требуемый

бъем памяти для хранения строковых данных. Все опе-

рации со строковы по

 

ками происходят в памяти в специально выделенном

ми

 

 

для них буфере strstreambufт. Строковые потоки позволяют облегчить формиро-

вание данных в памяти. В примере демонстрируется ввод данных в буфер, ко- пирование их в компоненту s класса string и их просмотр.

#includeл<strstrea> using namespace std;

class string

 

 

б

 

 

{ char s[80];

 

 

иpublic:

 

 

string(char *S) {for(int i=0;s[i++]=*S++;);}

Б void see(){cout<<s<<endl;}

};

 

 

void fun(const char *s)

 

 

{ strstream st;

//

создание объекта st

st << s << ends;

//

вывод данных в поток (в буфер)

string obj(st.str());

//

создание объекта класса string

151

st.rdbuf()->freeze(0);

// освобождение памяти в буфере

obj.see();

// просмотр скопированной из буфера строки

}

int main()

{fun("1234"); return 0;

}

Вначале создается объект st типа strstream. Далее при выводе переданной

в функцию символьной строки в поток добавлен манипулятор ends, который

соответствует добавлению ’\0’.

Р

Функция str() класса strstream обращается

непосредственно к хранимой в

И

буфере строке. Следует отметить, что при

обращении к функии str() объект st перестает контролировать эту память и при

 

У

уничтожении объекта память не освобождается. Для ее освобождения требуется

вызвать функцию st.rdbuf()−>freeze(0).

Г

Далее в примере показывается проверка состояния потока, чтобы убе-

диться в правильности выполняемых операций. Это позволяет, например, легко

определить переполнение буфера.

 

 

Б

 

 

 

#include <strstrea>

 

 

 

 

 

using namespace std;

 

 

 

к

 

void fun(const char *s,int n)

 

 

 

 

 

 

 

{ char *buf=new char[n];

 

 

// входной буфер

 

 

 

 

 

 

 

 

е

 

 

strstream st(buf,n,ios::in|ios::out);

// связывание потока st и буфера buf

 

st << s << ends;

 

 

т

// ввод информации в буфер

 

 

 

 

 

 

if(st.good()) cout << buf<<endl;

 

// проверка состояния потока

}

else cerr<<"error"<<endl;

 

 

// вывод сообщения об ошибке

 

 

 

 

и

 

 

 

 

int main()

 

 

 

 

 

л

о

 

 

 

}

 

 

 

 

 

 

{ fun("123456789",5);

 

 

 

 

fun("123456789",15);

 

 

 

 

 

 

 

б

 

 

 

 

 

 

 

return 0;

 

 

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

В результате выполнения программы получим:

Б

 

 

 

 

 

 

 

 

error

 

 

 

 

 

 

 

 

 

123456789

 

 

 

 

 

 

 

7.4. Организация работы с файлами

В языке С++ для организации работы с файлами используются классы потоков ifstream (ввод), ofstream (вывод) и fstream (ввод и вывод) (рис. 8).

Перечисленные классы являются производными от istream, ostream и iostream соответственно. Операции ввода−вывода выполняются так же, как и для других потоков, то есть компоненты-функции, операции и манипуляторы

152

могут быть применены и к потокам файлов. Различие состоит в том, как созда- ются объекты и как они привязываются к требуемым файлам.

ios

 

 

 

 

 

 

istream

 

 

 

ostream

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ifstream

 

 

 

 

 

 

 

 

ofstream

Р

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

iostream

 

 

 

 

И

 

 

 

 

 

 

 

 

 

 

fstream

 

 

У

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис.

8. Часть иерархии классов потоков вводавывода

 

В С++ файл открывается путем стыковкиГего с соответствующим пото-

 

 

 

 

 

 

 

 

 

а

 

 

 

 

 

 

ком. Рассмотрим организацию связыв ния потока с некоторым файлом. Для

этого используются конструкторы л ссов ifstreamБи ofsream:

 

 

ofstream(const char* Name, int nMode= ios::out, int nPot= filebuf::openprot);

 

 

 

 

 

 

е

 

 

 

 

 

 

 

 

 

 

ifstream(const char* Name, int nMode= ios::in, int nPot= filebuf::openprot);

 

Первый аргумент опр д кля т имя файла (единственный обязательный

параметр).

 

 

 

ает

 

 

 

 

 

 

 

 

 

 

 

о

 

режим для открытия файла и представляет бито-

 

Второй аргумент зад

 

вое ИЛИ ( | ) величин:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ios::app

при записи данные добавляются в конец файла, даже если теку-

щая позиция б

 

перед этим изменена функцией ostream::seekp;

 

ыла

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ios::ate указатель перемещается в конец файла. Данные записываются в

текущую позицию(произвольное место) файла;

 

 

ios::in поток создается для ввода; если файл уже существует, то он со-

и

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

храняется;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Б

бios::out

поток создается для вывода (по умолчанию для всех ofstream

объектов); если файл уже существует, то он уничтожается;

 

 

ios::trunc если

 

файл

уже существует,

 

его содержимое уничтожается

(длина равна нулю). Этот режим действует по умолчанию, если ios::out уста- новлен, а ios::ate, ios::app или ios:in не установлены;

ios::nocreate если файл не существует, функциональные сбои; ios::noreplace если файл уже существует, функциональные сбои; ios::binary ввод−вывод будет выполняться в двоичном виде (по умолча-

нию текстовой режим).

Возможны следующие комбинации перечисленных выше величин:

153

ios::out | ios::trunc удаляется существующий файл и (или) создается для записи;

ios::out | ios::app открывается существующий файл для дозаписи в конец файла.;

ios::in | ios::out открывается существующий файл для чтения и записи; ios::in | ios::out | ios::trunc существующий файл удаляется и (или) созда-

ется для чтения и записи;

ios::in | ios::out | ios::app открывается существующий файл для чтения и дозаписи в конец файла.

Третий аргумент данное класса filebuf используется для установки ат-

рибутов доступа к открываемому файлу.

 

 

 

 

Р

Возможные значения nProt:

 

 

 

 

filebuf::sh_compat режим совместного использования;

У

filebuf::sh_none режим Exclusive: не используется совместно;

 

filebuf::sh_read

режим совместного использования для чтенияИ;

filebuf::sh_write

режим совместного использования для записи.

 

Для комбинации атрибутов filebuf::sh_read и filebuf::sh write использу-

ется операция логическое ИЛИ ( || ).

 

 

Г

 

В отличие от рассмотренного подхода можно создать поток, используя

конструктор без аргументов. Позже вызвать фун циюБopen, имеющую те же ар-

 

 

к

 

 

гументы, что и конструктор, при этом второй

 

ргумент не может быть задан по

 

е

 

 

 

умолчанию:

 

 

а

 

 

void open(const char* name, int mode, int prot=fileout::openprot);

 

 

т

 

 

 

 

 

Только после того как по ок создан и со динен с некоторым файлом (ис-

пользуя либо конструктор с параме рами, либо функцию open), можно выпол- нять ввод информации в файл или вывод из файла.

#include iostream>

о

#include <fstream>

using namespace std;

 

 

 

 

и

#include "string.h"

 

class string

л

 

 

 

 

{ char *st;

 

 

 

 

б

 

 

int size;

 

 

 

publicи:

 

 

 

string(char *ST,int SIZE) : size(SIZE)

Б

 

 

 

 

{ st=new char[size];

 

strcpy(st,ST);

}

~string() {delete [] st;} string(const string &s) { st=new char[s.size];

154

//копирующий конструктор необходим, так как

//при перегрузке << в функцию operator переда-

 

strcpy(st,s.st);

// ется объект, содержащий указатель на строку, а

 

}

 

 

// в конце вызовется деструктор для объекта obj

 

friend ostream &operator<<(ostream &,const string);

 

 

friend istream &operator>>(istream &,string &);

 

};

 

 

 

 

 

 

 

ostream &operator<<(ostream &out,const string obj)

 

{ out << obj.st << endl;

 

 

 

 

 

}

return out;

 

 

 

 

 

 

Р

 

 

 

 

 

 

 

istream &operator>>(istream &in,string &obj)

{ in >> obj.st;

 

 

 

 

 

 

 

}

return in;

 

 

 

 

 

УИ

 

 

 

 

 

 

int main()

 

 

 

 

 

{ string s("asgg",10),ss("aaa",10);

БГ

 

 

int state;

 

 

 

 

 

 

 

ofstream out("file");

 

 

 

 

 

if (!out)

 

 

 

 

 

 

 

 

{ cout<<"ошибка открытия ф

 

"<<endl;

 

 

return 1;

// или exit(1)

йла

 

 

}

 

 

 

 

 

 

out<<"123"<<endl;

 

к

 

 

 

out<<s<<ss<<endl;

//

 

 

 

запись в файл

 

 

ifstream in("file");

е

 

 

 

 

while(in >> ss)

 

//

ч ение из файла

 

 

{cout<<ss<<endl;}

 

 

 

 

 

 

in.close();

 

т

 

 

 

 

 

out.close(); о

 

 

 

 

 

 

return 0;

 

 

 

 

 

 

 

}

и

 

 

 

 

 

 

В приведенномл

примере в классе содержится копирующий конструктор,

такикакбв функцию operator передается объект obj, компонентой которого явля- Бется строка. В инструкции cout <<s<<ss копирующий конструктор вызывается вначале для объекта ss, затем для s, после этого выполняется перегрузка в по- рядке, показанном ранее. При завершении каждой из функций operator<< (вна-

чале для s, затем для ss) будет вызван деструктор.

В операторе if (!out) вызывается (как и ранее для потоков) функция ios::operator! для определения, успешно ли открылся файл.

Условие в заголовке оператора while автоматически вызывает функцию класса ios перегрузки операции void *:

operator void *() const { if(state&(badbit|failbit) ) return 0;

155

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]