- •1. Понятие объектно-ориентированного программирования
- •2.Основные принципы ооп. Инкапсуляция
- •4. Конструкторы
- •Конструктор без параметров
- •Конструктор копирования
- •Деструкторы
- •Массивы объектов
- •Виртуальные методы
- •Использование классов функциональных объектов для настройки шаблонных классов
- •2. Стандартные потоки
- •3. Форматирование при вводе/выводе
- •4. Методы обмена с потоками
- •5. Ошибки потоков
- •6. Файловые потоки
- •7. Потоки и типы определяемые пользователем
- •Стандартная библиотека шаблонов stl (4 часа)
- •2. Контейнеры
- •3. Итераторы
7. Потоки и типы определяемые пользователем
Для ввода и вывода в потоках используются перегруженные для всех стандартных типов операции чтения и извлечения << и >>. При этом выбор конкретной операции определяется типом фактических параметров. Для того чтобы вводить и выводить величины типов, определенных пользователем, требуется перегрузить эти операции. Это бинарные операции, левым операндом которых является объект-поток, а правым – объект, который требуется извлечь или поместить в этот поток. Возвращаемое значение должно быть ссылкой на поток, чтобы можно было организовывать цепочки операций, как и в случае стандартных типов.
Рассмотрим пользовательский класс person.
class person{
char name[20];
int age;
public:
person(){name[0]='\0';age=0; }//конструктор без параметров
person( char[20] N,int A){strcpy(name,N);age=A;}//конструктор с параметрами
friend istream& operator>>(istream&,person&);//функция для ввода объекта из потока
friend ostream& operator<<(ostream&,const person&);//функця для вывода объекта в поток
char* getname(){return name;}//получить имя
int getage(){return age;}
int getpol(){return pol;}
};
Самая простая реализация перегруженных операций следующая:
istream& operator>>(istream&in, person&S)
{
in>>S.name;
in>>S.age;
return in;
}
ostream& operator<<(ostream& out, const person& S)
{
out<<S.name<<" "<<S.age<<endl;
return out;
}
При вводе возраста пользователь может сделать ошибку, в результате чего программа закончится аварийно. Поэтому надо реализовать функцию для ввода данных более надежным способом.
Напишем функцию
int GetInt(istream&in)//ввод целого числа из потока in
{
int value;
while(1)//бесконечный цикл
{
in>>value;//чтение целого числа
if(in.peek==’\n’)//если в буфере типа streambuf, связанном с потоком in находится //изображение целого числа, заканчивающегося ‘\n’, то после извлечения этого числа в //буфере останется только ‘\n’. Выполняется проверка этого условия.
{
in.get();//буфер очищается
break;//выход, т. к. число введено верно
}
else
{
cout<<”\nError in data; Repeat, please:”<<endl;
in.clear();//сбрасываются флаги ошибок потока in
while(in.get()!=’\n’{};//из буфера извлекаются все символы до символа ’\n’
}
}
return value;
}
Используя эту функцию можно реализовать функцию-операцию>> следующим образом:
istream& operator>>(istream&in, person&S)
{
in.getline(S.name,20);// читает из потока символы, пока не встретится символ ‘\n’ или пока не будет //прочитано 19 символов, прочитанные символы помещаются в массив S.name и к ним //добавляется ‘\0’.
S.age=GetInt(in);//вызов функции для ввода целого числа
return in;
}
Задание:
Написать функцию для ввода вещественного числа.
Выполнение лабораторной работы №7
Создание рабочего пространства:
Файл/New/Workspaces – создается пустое рабочее пространство и папка с именем этого пространства.
В рабочем пространстве создаются файлы:
Person.h - описание пользовательского класса;
Person.cpp - реализация пользовательского класса;
manipul.h – пользовательский манипулятор (см. выше);
file_work.h – работа с файлами (функции для поиска, удаления и замены данных в файле)
Создается проект Write_file для записи информации в файл
Файл/New/Project/Win32ConsoleApplication/установить флаг Add to current workspace/Empty project
В проект добавляются файлы Person.h, Person.cpp и создается файл write_f, в котором будет находиться основная функция main()
Создается проект Read_file для записи информации в файл
Файл/New/Project/Win32ConsoleApplication/Empty project
В проект добавляются файлы Person.h, Person.cpp, manip.h и создается файл read_f, в котором будет находиться основная функция main()
Аналогично 3 создается проект Add_file для добавления в файл.
Создается проект Del_file для записи информации в файл
Файл/New/Project/Win32ConsoleApplication/Empty project
В проект добавляются файлы Person.h, Person.cpp, file_work.h и создается файл del_f, в котором будет находиться основная функция main()
Аналогично 5 создается проект для замены записей в файле.
Переключаться между проектами рабочего пространства можно с помощью Project/Set Active Project
Рассмотрим файлы write_f.cpp, read_f.cpp, add_f.cpp, file_work.h, del_f.cpp и repl_f.cpp
//write_f.cpp - запись в файл
#include"person.h"
#include<iostream.h>
#include<fstream.h>
char*filename="..\\f.dat";
void main()
{
//запись в файл объектов person
person a;
ofstream out;//поток для записи в файл
out.open(filename);//открыть поток и связать с файлом
if(!out)//проверка открытия файлового потока
{
cout<<"\nCannot open file for writing\n";
return;
}
int n;
cout<<"\nHow many records would you like to get in?";
cin>>n;
cin.clear();//сбрасываются флаги ошибок потока cin
for(int i=0;i<n;i++)
{
cin>>a;
out<<a;
}
cout<<"\nwrite bytes:"<<out.tellp();//вывод размера файла
out.close();//закрыть поток
}
// read_f.cpp – чтение из файла
#include"person.h"
#include<iostream.h>
#include<fstream.h>
#include"manipuliator.h"
char*filename="..\\f.dat";
void main()
{
//чтение из файлового потока
person s,*mas;
fstream in(filename,ios::in);//открыть поток для чтения и связать с файлом
if(!in){cout<<"\nCannot open file for reading\n";return;}
for(int n=0;!in.eof();)
{
in>>s;
if(!in.eof())
n++;
}
cout<<"\nread objects:"<<n<<endl;
in.close();
in.open(filename,ios::in);
mas=new person[n];//выделить память под динамический массив
for(int i=0;!in.eof();)//чтение из файла в динамический массив
{
in>>s;
if(!in.eof())
{
mas[i]=s;
i++;
}
}
in.close();//закрыть поток
for( i=0;i<n;i++)//печать массива с использованием пользовательского манипулятора
cout<<mm(10,'#')<<mas[i];
delete[]mas;//удаление массива
in.close();
}
//добавление в файл
#include"person.h"
#include<iostream.h>
#include<fstream.h>
#include<stdlib.h>
char*filename="..\\f.dat";
void main()
{
person a;
int n;
filebuf buf;//создать объект buf класса filebuf
buf.open(filename,ios::app);//открыть его для добавления и связать с файлом
ostream out(&buf);//создать поток и связать с buf
cout<<"\nHow many records would you add to file?";
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a;//прочитать объект
out<<a;//записать в файловый поток
}
buf.close();//закрыть файл
}
//file_work.cpp
#include<iostream.h>
#include<fstream.h>
#include<string.h>
#include<stdio.h>
//глобальные переменные
char*tempname="..\\temp";
char*filename="..\\f.dat";
int find(char s[20])
//возвращает номер байта
{//поиск по ключу
fstream stream(filename,ios::in);//открыть файловый поток для ввода
if(!stream){cout<<"\nCannot open file for reading\n";return -2; }
person a;
int ok=0;
int place=0;
do
{
place=stream.tellg();//текущая позиция
stream>>a;
if(!stream.eof())
if(strcmp(a.getname(),s)==0)//сравнить ключ с фамилией
{
ok=1; break;;
}
}
while (!stream.eof());
stream.close();
if(ok&&place>0) return place-1;
if(ok&&place==0)return 0;//если объект самый первый
else return -1;//вернуть -1, если объект не найден
}
void del(ifstream& stream,int x)
{//удаление записи с позиции х
ofstream out(tempname);//открыть вспомогательный файл для записи
if(!out){cout<<"\nCannot open file for writing\n";return;}
char*buf;//буфер для чтения информации из файла
buf=new char[x];
stream.read(buf,x);//прочитать х символов в буфер из исходного файла
out.write(buf,x);//записать во вспомогательный файл
out.flush();
person a;
stream>>a;
if(!stream&&!stream.eof()){cout<<"Cannot reading!\n";return;}
cout<<"\n"<<a<<" - is deleting. . .\n";
while(!stream.eof())
{
stream>>a;
if(!stream.eof())
{
out<<a;
if(!out){cout<<"Cannot writing!\n";return;}
}
}
stream.close();
out.close();
remove(filename);
rename(tempname,filename);
}
void repl(ifstream& stream,int x,tovar &b) //замена записи с позиции х
{
ofstream out(tempname);//открыть вспомогательный файл для записи
if(!out){cout<<"\nCannot open file for writing\n";return;}
char*buf;//буфер для чтения информации из файла
buf=new char[x];
stream.read(buf,x);//прочитать х символов в буфер из исходного файла
out.write(buf,x);//записать во вспомогательный файл
out.flush();
person a;
stream>>a;
if(!stream&&!stream.eof()){cout<<"Cannot reading!\n";return;}
cout<<"\n"<<a<<" - is replacing. . .\n";
out<<b;
//записать конец файла
while(!stream.eof())
{
stream>>a;
if(!stream.eof())
{
out<<a;
if(!out){cout<<"Cannot writing!\n";return;}
}
}
stream.close();
out.close();
remove(filename);
rename(tempname,filename);
}
//del_f.cpp – удаление из файла
#include"person.h"
#include<iostream.h>
#include<fstream.h>
#include"file_work.h"
void main()
{
person a;
int x;
ifstream in(filename);
//удаление из файла
cout<<"\nInput the deleting name:";
char s[20];
cin>>s;
x=find(s);//позиция в файле, с которой начинается удаление
if(x>=0) del(in,x);
else cout<<"\nThere isn\'t record with such name";
in.close();
}