Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ТП лекции Раздел 4.doc
Скачиваний:
16
Добавлен:
28.09.2019
Размер:
2.56 Mб
Скачать

4.10.3. Использование библиотеки классов потокового ввода-вывода.

В языке C++, так же, как и в С, не предусмотрены какие-либо встроенные функ­ции или операторы ввода-вывода. Эти действия осуществляются с помощью функ­ций внешних библиотек, определенных в файлах заголовков, таких как stdio.h, stdiostr.h, iostream.h и других. Процедуры ввода-вывода библиотеки, на кото­рую ссылается iostream.h, осуществляют преобразование значений переменные стандартных типов, таких как int или double, в последовательность символов, и наоборот. В библиотеке описан класс iostream, в котором операция << переопре­делена так, чтобы вывод в поток данных всех стандартных типов языка C++ был максимально простым и удобным. Операция >> переопределена в классе istream для ввода данных стандартных типов. Для ввода и вывода внутренних данных классов, опре­деленных пользователем, операции >> и << должны быть переопределены в этих клас­сах.

В библиотеке определен объект cout класса ostream, который связан ее стандартным потоком вывода и является аналогом потока stdout в библиотеке stdio.h. Объект сеrr -поток вывода сообщений об ошибках ввода-вывода, clog — поток вывода сообще­ний пользователю. Объект cin класса istream обозначает стандартный поток ввода.

Оператор cout<<i; интер­претируется как cout.operator<<(i);. Так как тип возвращаемого значения операции - ostream&, то возможна цепоч­ка последовательного вывода. Оператор cout<<I<<j; интерпретируется как (cout.operator<<(i)).operator<<(j);.

#include <iostream>

using namespace std;

class Man // Класс объектов

{

private: // Секция закрытого доступа

char Name[20];

unsigned int Age; // Скрытые внутренние данные

public: // Секция открытого доступа

void in ()// Метод класса

// Здесь те же коды, что и ранее

{ // Метод (функция) ввода

cout<<"Type Man"<<endl<<"Name: ";

cin>>Name;

// Name = strcpy(new char[strlen(buff)+1], buff);

cout<<" Age: ";

cin>>Age;

}

void out ()

{ // Метод класса

cout<<Name<<" "<<Age;

}

};

int _tmain(int argc, _TCHAR* argv[])

{

int i;

//==Демонстрация использования класса ====//

Man m; // Объект m класса Man

m.in(); m.out (); // Ввод, вывод данных

//m.Age = -2000; //Этот оператор ошибочен и ошибка

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

cin>>i;

return 0;

}

void main() //Подключите iostream.h

{

char с = 'С', str[80];

int i = -32767;

float v = 2.99792e8, t=3, s=0.;

double perm=12.5664E-7;

//= = = = = = = Вывод в поток cout = = = ====//

cout <<\n i=" << i;

cout << "\n c=" << c;

cout << "\n s+vt= " << (s+v*t) << " m" << "\n Open space permiability = "<<perm; cout << "\nEnter fn integer : "; cin >> i; cout << "\nA real : "; cin >> s: cout << "\nA string of chars: ": cin >> str; cout << "\nYou entered: "<<i<<' '<<s<<' '<<str<<endl;

}

Результат работы этой программы:

i=-32768

с=С

s+vt= 8.99376e+08 m

Open space permiability = 1.25664e-06 и т.д.

Пример иллюстрирует использование операций >> и << для ввода и вы­вода стандартных типов. Для ввода и вывода переменных нестандартных типов, например, объектов класса Vector, операции << и >> следует переопределить в классе Vector. С этой целью дополним класс описанием friend-функций и реали­зуем их тела вне блока описания:

friend ostream& operator<<(ostream&, Vector& v);

friend istream& operator>>(istream&, Vector& v);

ostream& operator<<(ostream& os, Vector& v)

{return os<<"\n Vector: xl="<<v.xl<<" x2="<<v.x2;}

istreams operator>>(istream& is, Vector& v)

{

double dl, d2;

cout << "\n xl= "; is » dl;

cout << " x2= "; is » d2;

v=Vector (dl, d2); // Создание объекта

return is; // Входной поток

}

Первый формальный параметр (&os) функции operator<< — ссылка на объект класса ostream. С ним связан стандартный поток cout. Второй параметр является ссылкой на объект класса Vector. Функция возвращает адрес выходного потока. Аналогичный комментарий можно дать и для переопределенной операции вво­да. Теперь можно вводить и выводить объекты класса Vector. Добавьте в функ­цию следующий код для проверки изменений:

Vector х, у; //Переопределенные операции ввода-вывода cout << "\n\n Enter vector:"; cin >> x; cout << "\n Enter one more:"; cin >> y; cout << "\n\n You have entered: " << x <<y; cout << "\n The norm of |x+y|="<< !(x+y) << "\n\n";

В целом библиотека потоковых классов C++ состоит из многих классов, объе­диненных в два иерархических дерева. Класс streambuf является базовым клас­сом для классов filebuf, stdiobuf и strstreambuf, обеспечивающих буферизованный интерфейс между данными пользователя и такими областями хранения данных, как память или физическое устройство. Более 30 методов класса streambuf по­зволяют выбирать символы из буфера, помещать их туда, позиционировать указатель, запрашивать количество оставшихся символов в буфере и т. п. Мето­ды производных классов (само определение производного класса будет дано в следующем разделе) позволяют открывать и закрывать файлы, манипулировать дескриптором файла, управлять вводом-выводом на консоль, создавать буфер для форматирования строки символов в памяти. Второй базовый класс ios по­рождает дерево классов istream, ostream, iostream. Каждый из этих классов, в свою очередь, имеет несколько производных классов. В результате дерево состоит из более чем 10 классов, методы которых дают возможность производить ввод-вы­вод с использованием операций форматирования высокого уровня. Подробное описание этих многочисленных функций невозможно дать в объеме лекций, поэтому рассмотрим лишь один пример использования некоторых из классов библиотеки:

void main()

{

int с;

const char *fn = "test.txt";

ofstream fOut: // Объявление выходного потока

streambuf *bufOut, *bufln = cin.rdbufO;

// Открыть файл, встать в конец, разрешить дозапись

fOut.open (fn, ios::ate | ios::app);

if (IfOut) cerr « "Can't open " « fn: exit(-l);

bufOut = fOut. rdbuf (); // Связывание of stream и streambuf

clog«"Enter some text (AZ - to stop)"«endl;

// Ввод с клавиатуры, вывод на экран и в файл

while ((c=bufln->sbumpc()) != EOF)

{

cout « char (с); //Эхо на экран

if (bufOut->sputc(c) == EOF) cerr « "Output error";

}

fOut.close();

// Позиционирование во входном потоке

int Size = 0;

// Объявление входного потока и попытка его открытия

ifstream fin (fn, ios::in | ios::nocreate);

fin. seekg (OL.ios:: end); // Переместиться в конец файла

if ((Size = fln.tellg()) < 0)

{

сегг « fn « " not found"; exit(-l);

}

cout«fn«" Size = "«Size«endl;

}

Сначала в примере создается файл test.txt, в который вводится фрагмент текста. Класс ofstream происходит от класса ostream (смысл выражения «проис­ходит от классов» прояснится в следующем разделе). Следующая строка про­граммы streambuf *bufOut, *bufln = cin.rdbuf();: определяет два указателя на класс streambuf, которые используются для управления буферами потоков выво­да и ввода. Метод cin.rdbuf() возвращает текущее значение указателя в потоке ввода, связанном с клавиатурой. Оператор

fOut.open (fn, ios::ate | ios::app);

обращается к методу open класса ofstream, который открывает файл с именем, переданным первым параметром в режиме, заданном вторым параметром. Вто­рой параметр является выражением, операнды (ate и арр) которого определены в классе ios. Они являются элементами перечисления enum openjnode и допуска­ют выполнение логических операций над собой с целью задания набора битовых признаков режима открытия файла. В нашем случае объединяются признаки арр (разрешение добавлять в конец файла) и ate (режим перемещения в конец фай­ла при его открытии). Операция ! переопределена так, что нулевой код возврата свидетельствует об ошибке при открытии файла. Сообщение об ошибке выво­дится в поток сегг, который обычно направлен на экран монитора. Оператор bufOut = fOut.rdbuf(); связывает буфер вывода с выходным потоком, так как метод rdbuf класса ofstream возвращает текущее значение указателя потока (фай­ла), которое присваивается указателю bufOut типа streambuf*.

В цикле while осуществляется последовательный ввод символов из входного потока, вывод их сначала на экран cout«char(c);, затем в буфер, связанный с фай­лом. Метод sbumpc класса streambuf возвращает текущий символ буфера ввода и сдвигает указатель буфера на следующий символ. Аналогичным образом метод sputc помещает символ в буфер вывода. Символ Ctrl+z служит признаком конца файла (EOF — End Of File). Чтобы закончить ввод с клавиатуры, необходимо ввес­ти такую последовательность: Enter, ^Z, Enter. Следующая часть программы иллюс­трирует, как можно позиционировать указатель в файле. Указатель переводится в конец созданного файла, и выясняется его позиция относительно начала файла. Таким образом определяется размер файла в байтах. Класс ifstream происходит от классов istream. Наличие двух аргументов при объявлении объекта заставляет выбрать один из конструкторов класса ifstream, который сразу открывает файл с именем, переданным первым параметром, и в режиме, задаваемом вторым пара­метром. Режим задан в виде выражения ios::in | ios: :nocreate. Результатом по­битовой операции ИЛИ является установка двух признаков — открыть файл для ввода и не создавать файл, если он не существует. Позиционирование в файле осуществляется с помощью функции seekg, которая определена в классе istream и наследуется классом ifstream. Результатом вызова будет перемещение указателя потока в конец файла. Метод tellg класса istream возвращает значение текущей позиции потока, которое численно на единицу меньше размера файла в байтах.

Тема 4.11. Методы повышения гибкости и надежности объектно-ориентированных программ в Visual C++.