Главная->Інформатика та програмування->Содержание->Как объекты записывают и читают сами себя

ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 12) онлайн

Как объекты записывают и читают сами себя

Иногда имеет смысл разрешить каждому компоненту класса читать и записы- вать самого себя. Это довольно прозрачный подход и отлично работает, если нужно писать и читать небольшое число объектов. В нашем примере мы добави- ли два метода — diskOut() и diskIn() — в класс person. Эти функции позволяют объектам person записывать себя в файл и читать себя же из него.

Примем некоторые упрощающие допущения. Во-первых, все объекты будут храниться в одном и том же файле PERSFILE.DAT. Во-вторых, новые объекты всег- да будут добавляться к концу файла. Аргумент функции diskIn() позволяет читать данные о любом человеке из файла. Для предотвращения попыток прочитать данные, выходящие за пределы файла, мы включаем в программу статический метод diskCount(), возвращающий число людей, информация о которых хранится в файле. При вводе данных следует использовать только фамилии людей, про- белы не допускаются.

 

Листинг 12.16. Программа REWOBJ

// rewobj.cpp

// Файловый ввод/вывод объектов person

#include <fstream>           // Для файловых потоков

#include <iostream>

using namespace std;

///////////////////////////////////////////////////////////

class person                 // класс person

  {

  protected:

    char name[40];           // имя человека

    int age;                 // его возраст

  public:

    void getData(void)       // получить данные

      {

      cout << "\n  Введите фамилию: "; cin >> name;

      cout << "  Введите возраст: "; cin >> age;

      }

    void showData(void)      // Вывод данных

      {

      cout << "\n  Имя: " << name;

      cout << "\n  Возраст: " << age;

      }

    void diskIn(int);        // чтение из файла

    void diskOut();          // запись в файл

    static int diskCount();  // Число человек в файле

  };

//---------------------------------------------------------

void person::diskIn(int pn)  // Чтение данных о числе

                             // человек pn из файла

  {                  

  ifstream infile;           // создать поток

  infile.open("PERSFILE.DAT", ios::binary);  // открыть его

  infile.seekg( pn*sizeof(person) );         // сдвиг

                                             // файлового указателя

  infile.read( (char*)this, sizeof(*this) ); // чтение данных

                                             // об одном человеке

  }

//---------------------------------------------------------

void person::diskOut()       // запись в конец файла

  {

  ofstream outfile;          // создать поток

                             // открыть его

  outfile.open("PERSFILE.DAT", ios::app | ios::binary);

  outfile.write((char*)this,sizeof(*this)); //записать в него

  }

//---------------------------------------------------------

int person::diskCount()      // число людей в файле

  {

  ifstream infile;

  infile.open("PERSFILE.DAT", ios::binary);

  infile.seekg(0, ios::end); // перейти на позицию «0 байт

                             // от конца файла»

                             // вычислить количество людей

  return (int)infile.tellg() / sizeof(person);

  }

///////////////////////////////////////////////////////////

int main()

{

  person p;                  // создать пустую запись

  char ch;

   

  do {                       // сохранение данных на диск

    cout << "Введите данные о человеке: ";

    p.getData();             // Получить данные

    p.diskOut();             // записать на диск

    cout << "Продолжить (y/n)? ";

    cin >> ch;

    }  while(ch=='y');       // цикл до 'n'

 

  int n = person::diskCount(); // сколько людей в файле?

  cout << "В файле " << n << " человек(а)\n";

  for(int j=0; j<n; j++)       // для каждого

    {

    cout << "\nПерсона " << j;

    p.diskIn(j);               // считать с диска

    p.showData();              // вывести данные

Листинг 12.16 (продолжение)

    }

  cout << endl;

  return 0;

}

 

Здесь для вас не должно быть новых откровений. Большинство элементов этой программы уже встречались. Она работает примерно по тому же принципу, что и DISKFUN. Тем не менее имейте в виду, что все подробности дисковых опе- раций невидимы для main(), они спрятаны внутрь класса person.

Заранее никогда неизвестно, где находятся данные, с которыми мы собираем- ся работать, так как каждый объект находится в своей области памяти. Но указа- тель this всегда подскажет, где мы находимся во время выполнения какого-либо метода. В потоковых функциях read() и write() адрес объекта, который будет читаться или записываться, равен *this, а его размер — sizeof(*this).

Вот результат работы программы при предположении, что до начала ее рабо- ты в файле уже было две записи:

Введите данные о человеке: Введите имя: Гребеньков Введите возраст:19 Продолжить (y/n)? У

 

Введите данные о человеке: Введите имя: Андреанов Введите возраст:20 Продолжить (y/n)? N

 

Персона #1 Имя:Ершова Возраст:21 Персона #2 Имя:Малахова Возраст:20 Персона #3 Имя:Гребеньков Возраст:19 Персона #4

Имя:Андреанов            

Возраст: 20

               

Чтобы пользователь мог ввести собственное имя файла, вместо жесткого закре- пления его в программе, как мы делали в предыдущих примерах, следует создать статическую компонентную переменную (например, charfileName[]), а также ста- тическую функцию для ее установки. Можно сделать и по-другому: каждый объ- ект записывать в свой файл. Для этого понадобится нестатическая функция.

 

37