Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP / Практика 1.pdf
Скачиваний:
30
Добавлен:
20.04.2015
Размер:
125.24 Кб
Скачать

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

cout « "Введите данные о человеке: "; p.getData ();

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

//записать на диск

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

cin » ch:

 

}

 

while(ch=='y');

// цикл

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

cout « "В файле " « n « " человек(а)\n"; for(int j=0; j<n; j++) // для каждого

{

cout « "\nПерсона " « j; p.diskln(j);

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

//вывести данные

}

cout « endl; return 0;

}

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

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

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

Статические функции

Одним из способов записать за один сеанс множество объектов является употребление статической функции, которая применяется ко всему классу в целом, а не к отдельным его объектам. Такая функция действительно может записать все объекты сразу. Но как она узнает, где находятся объекты? Она обратится к массиву указателей на объекты, который можно хранить в виде статической переменной. При создании каждого объекта его указатель заносится в этот массив. Статический элемент данных также может свято хранить память о том, сколько всего объектов было создано. Статическая функция writeQ откроет файл, в цикле пройдет по всем ссылкам массива, записывая по очереди все объекты, и после окончания записи закроет файл.

Размеры порожденных объектов

Чтобы жизнь медом не казалась, давайте сделаем следующее предположение: объекты, хранящиеся в памяти, имеют разные размеры. Почему и когда такое бывает? Типичной предпосылкой этого является создание порожденных классов. Например, рассмотрим классы employee, выступавший как базовый для классов manager, scientist и laborer. Объекты этих трех порожденных классов имеют разные размеры, так как содержат разные объемы данных. Например, в дополнение к имени и порядковому номеру, которые присущи всем работникам, у менеджера есть еще такие поля данных, как должность и членские взносы гольф-клуба, а у ученого есть поле данных, содержащее количество его публикаций.

Нам хотелось бы записать данные из списка, содержащего все три типа порожденных объектов, используя простой цикл и метод write () класса ofstream. Но нам нужно знать размеры объектов, чтобы передать их в качестве второго аргумента этой функции.

Пусть имеется массив указателей аrrар[], хранящий ссылки на объекты типа employee. Указатели могут ссылаться, таким образом, и на все три порожденных класса. При использовании виртуальных функций можно использовать выражения типа

arrap[]->putdata();

Тогда будет поставлена на исполнение во время работы программы версия putdata (), соответствующая объекту, на который ссылается указатель, а не та, что соответствует базовому классу. Можно ли использовать sizeof () для вычисления размера ссылочного аргумента? То есть можно ли написать, например, такое выражение:

ouf.write( (char*)arrap[j]. sizeof(*arrap[j]) ); //плохо это

Увы, нельзя, потому как sizeof () не является виртуальной функцией. Она не в курсе, что нужно обращаться к типу объекта, на который ссылается указатель, а не на тип самого указателя. Эта функция всегда будет возвращать размер объекта базового класса.

Использование функции typeid()

И все-таки, как же нам найти размер объекта, если все, что мы имеем, это указатель на него? Одним из решений является, несомненно, функция typeid (). Можно использовать ее для определения класса объекта, подставляя имя этого класса в качестве аргумента sizeof (). Чтобы использовать typeid (), надо включить параметр компилятора RTTI. (это существенно только для компилятора Microsoft Visual C++).

if (typeid (*this) == tipeid (object)

...

Соседние файлы в папке OOP