Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
117
Добавлен:
10.12.2013
Размер:
856.06 Кб
Скачать

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

  1. Создание рабочего пространства:

  • Файл/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();

    }

  • Соседние файлы в папке II cemecTP