- •Билет №16.
- •1. Структурований тип даних - запис. Доступ до полів запису. Операції над полями запису та над записами.
- •Пример программы c записью Паскаля
- •Оператор присоединения или как избавиться от префикса
- •Пример фрагмента программы c записью и префиксом Паскаля
- •2. Опис класу. Створення та вилучення об’єктів в Delphi.
Пример программы c записью Паскаля
program primer 2 ; type anketa=record fio: string[45]; dat_r: string[8]; adres: string[50]; curs: 1..5; grupp: string[3] end; var student: array [1..100] of anketa; I: integer; begin {последовательно вводим каждую запись} for I:=1 to 100 do begin writeln (‘введите сведения о’, I , ‘-м студенте’); writeln (‘введите фамилию, имя и отчество’); readln (student[I].fio); writeln (‘введите дату рождения’); readln (student[I].dat_r); writeln (‘введите адрес’); readln(student[I].adres); writeln (‘введите курс’); readln(student[I].curs); writeln (‘введите группу’); readln (student[I].grupp); end; writeln (‘ввод закончен’); writeln ; {просматриваем массив записей и выбираем только студентов 2-го курса } for I:=1 to 100 do if student[I].curs=2 then writeln(‘ фамилия студента : ’, student[I].fio); end.
Оператор присоединения или как избавиться от префикса
Префикс – обязательная предшествующая часть составного идентификатора для имен полей в структуре типа запись Паскаля. Очень часто у программиста возникает желание не указывать префикс в имени полей, например, когда идет постоянное использование одних и тех же записей. В языке Паскаль предусмотрена такая возможность, реализуемая при помощи оператора присоединения, который в общем виде выглядит так:
with <имя_записи> do <действие с полем записи>;
Следует обратить внимание на то, что после служебного слова do может стоять только один оператор, но он может быть составным (любая последовательность операторов, заключенная в операторные скобки begin end ).
Например, фрагмент из предыдущей программы с использованием оператора присоединения будет выглядеть так:
Пример фрагмента программы c записью и префиксом Паскаля
for I:=1 to 100 do with student[I] do begin writeln (‘введите сведения о’, I , ‘-м студенте’); writeln (‘введите фамилию, имя и отчество’); readln (fio); writeln (‘введите дату рождения’); readln (dat_r); writeln (‘введите адрес’); readln(adres); writeln (‘введите курс’); readln(curs); writeln (‘введите группу’); readln (grupp); end;
2. Опис класу. Створення та вилучення об’єктів в Delphi.
Для создания классов в Object Pascal введена конструкция class:
Type TmyClassA = class(имя класса-родителя) End;
или
TmyClassB = class End;
"Так просто?" - скажете вы. Да, действительно просто - мы создали новый тип данных - класс TmyClassA (TmyClassB). И хотя мы еще ничего не сказали о том, что это за класс объектов, как будут вести себя объекты этого класса, какие они будет иметь свойства и многое другое, это все же настоящий класс объектов, который умеет уже очень многое!
Дело в том, что в Object Pascal все классы наследуются от базового класса TObject, который представляет из себя корень всей будущей иерархии классов, эдакий "первокирпичик". Этот "первокирпичик" умеет создавать свои экземпляры, уничтожать их, давать информацию о своем имени, имеет диспетчер сообщений и еще массу полезных функций, без которых не может существовать ни один класс. Если в заголовке класса не указан "родитель", то класс просто наследуется от TObject. Т.е. описание класса TmyClassB в данном случае равносильно следующей конструкции:
Type TmyClassB = class(TObject) End;
Попробуем теперь наш класс в действии. Но для начала следует подготовить плацдарм для боевых действий.
Запускаем Delphi, создаем новый проект (File -> New application). Затем убираем из проекта модуль Unit1 (Project -> Remove from project, выбираем Unit1 и нажимаем OK). В проекте остается только файл project.dpr. Стираем весь текст и оставляем только следующие строки:
Program ClassTest; {$AppType Console} Uses Windows; {$R *.RES} Begin End.
Все готово. Обратите внимание на 2-ю строку: {$AppType Console} . Это - команда компилятору собрать консольное приложение, т.е. приложение, работающее в текстовом режиме, подобно старым DOS-программам, написанным на Turbo Pascal. При этом программа остается полноценным Win32-приложением. Этого же результата можно добиться, открыв Опции проекта (Project -> Options...) и на вкладке Linker поставить галочку в пункте Generate console application. Таким образом мы на время избавили себя от необходимости изучения графического интерфейса Windows и получили простую возможность вывести результаты нашей работы на дисплей.
Ну а теперь приступим к испытаниям. Описание класса подобно проекту автомобиля, по которому на заводе собирают готовые экземпляры автомобилей. На проекте ездить нельзя :), а вот на автомобиле, собранном по этому проекту - пожалуйста. Точно так же следует поступить и нам:
Type TmyClassA = class(TObject) End; TmyClassB = class End; Var ObjA: TmyClassA; { Описание переменной типа TmyClassA } ObjB: TmyClassB; { Описание переменной типа TmyClassB } Begin ObjA := TmyClassA.Create; ObjB := TmyClassB.Create;
Мы создали экземпляры классов TmyClassA и TmyClassB (или собственно объекты) при помощи конструктора Create. Вообще каждый класс имеет конструктор (один или несколько) и деструктор. Цель конструктора - создание экземпляра (объекта) указанного класса. Ну а цель деструктора, как вы догадались - уничтожение объекта, надобность в котором отпала. В данном случае мы воспользовались конструкторами, унаследованными обоими классами от базового класса TObject. Конструктор класса создает объект в динамической памяти и возвращает ссылку на него, которую мы помещаем в переменную ObjА (ObjB).
У каждого класса есть имя и родительский класс, которые можно получить, вызвав методы ClassName (ИмяКласса) и ClassParent (РодительскийКласс):
Writeln('Class name:',objA.Classname, ' ', 'Parent:',objA.ClassParent.ClassName); Writeln('Class name:',objB.Classname, ' ', 'Parent:',objB.ClassParent.ClassName); readln;
Как мы видим, оба класса имеют "родителя" - TObject. Естественно, возникает вопрос, а каким образом мы можем узнать, в каких "родственных отношениях" находятся созданные объекты? Это можно узнать несколькими способами.
при помощи методов ClassType (ТипКласса) и InheritsFrom (УнаследованОт):
Writeln('Is the ObjA instance of TmyClassA?', ObjA.ClassType = TmyClassA); Writeln('Is the ObjA instance of TmyClassB?', ObjA.ClassType = TmyClassB); Writeln('Is the ObjA instance of TObject?', ObjA.ClassType = TObject); Writeln('Is the ObjA descendant of TObject?', ObjA.InheritsFrom(TObject)); Writeln('Is the ObjA descendant of TmyClassB?', ObjA.InheritsFrom(TmyClassB));
при помощи оператора is:
Writeln('Is the ObjA instance of myClassA?', ObjA is TmyClassA); Writeln('Is the ObjA descendant of TObject?', ObjA is TObject);
Следует отметить, что выражение:
Writeln('Is the ObjA instance of myClassB?', ObjA is TmyClassB);
будет отметено компилятором еще во время компиляции, т.к. ObjA действительно не может быть экземпляром класса TmyClassB. Зато возможна следующая ситуация:
var Obj1, Obj2: TObject; begin Obj1 := TmyClassA.Create; Obj2 := TmyClassB.Create;
Мы описали две переменных типа TObject, в которые затем поместили ссылки на созданные экземпляры классов TmyClassA и TmyClassB. Да-да, и такая ситуация возможна! Представьте себе две коробки, на которых написано - "Яблоки". В одну мы положим антоновку, а в другую - белый налив. И это будет вполне естественно. А вот положить сливы в коробку из-под яблок будет несколько нечестно :). В таком случае мы можем не знать, какие яблоки лежат в коробках, но мы точно знаем, что лежат там именно яблоки.
В этой ситуации компилятор спокойно "переварит" приведенный текст:
Writeln('Is the Obj1 instance of myClassA?', Obj1 is TmyClassA); Writeln('Is the Obj1 descendant of TObject?', Obj1 is TObject); Writeln('Is the Obj1 instance of myClassB?', Obj1 is TmyClassB);
так как реальный тип объекта, содержащийся в Obj1, еще не известен, но точно известно, что это будет наследник от TObject. A т.к. TmyClassB тоже унаследован от TObject, то последняя строчка вполне корректна.
Уфф! Наработались? Теперь надо за собой убрать.
ObjA.Destroy; ObjB.Destroy;
Destroy - это деструктор. Деструктор производит все завершающие действия по корректному завершению работы объекта и затем уничтожает его. После вызова деструктора ссылка, лежащая в переменной ObjA (ObjB) становится недействительной, и ее использование может привести к непредсказуемым результатам!
Но непосредственное использование деструктора в Object Pascal не рекомендуется. Более правильно для уничтожения объекта использовать метод free:
ObjA.free; ObjB.free;
Free проверяет, не является ли ссылка на объект пустой (nil), и если ссылка не пуста, вызывает деструктор.
Но пока классы TmyClassA и TmyClassB остаются вещью в себе. Чтобы экземпляры наших новых классов обрели хоть какой-то смысл, надо наполнить их содержимым. Этим мы и займемся далее.
