Тема 3.1. 1.Основные принципы объектно-ориентированного программирования. Классы: основные понятия.

План:
1. Объектная модель
2. Объекты и классы
3. Поля
4. Свойства
5. Методы
6. Управление доступом к классу
Объектная модель
Объектно-ориентированным языкам программирования присущи три основные черты – инкапсуляция, наследование и полиморфизм.
Инкапсуляция – это объединение данных с процедурами и функциями для получения нового типа данных – класса.
Класс в Delphi представляет собой единство трех сущностей – полей, методов и свойств. Инкапсуляция позволяет во многом изолировать класс от остальных частей программы, сделать его «самодостаточным» для решения конкретной задачи. В результате класс всегда несет в себе некоторую функциональность. Например, класс Tform содержит (инкапсулирует в себе) всё необходимое для создания Windows-окна, класс Ttimer обеспечивает работу программы с таймером и т.д.
Наследование – это определение класса и его дальнейшее использование для построения иерархии порождённых классов с возможностью доступа для каждого порождённого класса к коду и данным предка. Порожденный класс автоматически наследует поля, методы и свойства родителя и может дополнять их новыми. Таким образом, принцип наследования обеспечивает поэтапное создание сложных классов и разработку собственных библиотек классов.
В Delphi существует предопределённый класс TObject, который служит неявным предком тех классов, для которых предок не указан. Класс Tobject выступает корнем иерархии классов. Он содержит ряд методов, которые по наследству передаются всем остальным классам (Create, Destroy и др.).
Механизмы наследования полей, свойств и методов различаются.
Порождённый класс наследует от родителя все поля данных. Доступ к полям предка осуществляется по именам (так, как если бы они были определены в потомке). В наследниках можно определять новые поля, но их имена должны отличаться от имён предка.
Свойство базового класса можно перекрыть (override) в производном классе, например, чтобы добавить ему новый атрибут доступа или связать с другим полем или методом.
Метод базового класса тоже можно перекрыть в потомке. При этом в наследнике можно вызвать перекрытый метод предка, указав перед именем метода зарезервированное слово inherited.
Полиморфизм – это использование одинаковых имён методов на разных уровнях иерархии. При этом каждый класс реализует метод удобным для него образом. Полиморфизм обеспечивает классам возможность решать схожие по смыслу проблемы разными способами. В Delphi поведенческие свойства класса определяются набором входящих в него методов. Изменяя алгоритм того или иного метода в потомках класса, программист может придавать этим потомкам отсутствующие у родителя специфические черты. Для изменения метода необходимо перекрыть его в потомке, то есть объявить в потомке одноименный метод и реализовать в нем нужные действия. В результате в объекте-родителе и объекте-потомке будут действовать два одноименных метода, имеющие разную алгоритмическую основу и, следовательно, придающие объектам разные свойства.
Объекты и классы
Концепция объектно-ориентированного программирования основана на понятиях объекта и класса.
Классом в Delphi называется тип данных, содержащий поля, методы и свойства. Как и любой другой тип, класс даёт обобщённое описание, служащее образцом для создания конкретных экземпляров реализации.
В языке Delphi (Object Pascal) объекты – это программные конструкции, формируемые классами. Объект является конкретным экземпляром класса. Класс определяет категорию объектов, содержит как объявление данных, так и функции их обработки. Пользователю, как правило, предоставляется описание класса, а не его реализация. Главная забота класса – скрыть как можно больше информации. Объекты же – это конкретные представители класса, экземпляры класса.
Важным отличием классов от других типов является то, что экземпляры класса всегда распределяются в куче. Объекты фактически представляют собой лишь указатели на динамическую область памяти.
Классы определяются в секции type глобального блока. По форме объявления классы похожи на записи. Описание класса начинается служебным словом class и завершается словом end. Объекты описываются в разделе var.
Поля класса аналогичны полям записи и служат для хранения данных. Методами называют процедуры и функции, предназначенные для обработки полей. Свойства реализуют механизм доступа к полям.
В описание класса включаются заголовки методов, которые играют роль предварительных объявлений. Программный код методов помещается ниже определения класса. В программе может быть объявлено несколько объектов, принадлежащих к одному классу.
Type
TMyClass = class(TParentClass)
<поля>;
<свойства>;
<методы>;
. . .
end;
Var
MyClass1, MyClass2: TMyClass;
MyClass1, MyClass2 – это ссылки на объекты, которых ещё физически не существует. Объекты появятся в процессе работы программы. После создания объект можно использовать в программе. Доступ к полям и методам объекта выполняется с помощью составных имён:
<имя объекта>.<имя поля>
<имя объекта>.<имя процедуры>
Для сокращения текста кода можно использовать оператор with.
Когда объект станет не нужен, он должен быть уничтожен вызовом специального метода. Объекты могут выступать в программе не только в качестве простых переменных, но и в качестве элементов массивов, полей записей, параметров процедур и функций. Объекты могут служить полями других объектов.
Поля
Полями называются инкапсулированные в классе данные. Поля могут быть любого типа, в том числе – классами. Имена полей должны начинаться с буквы f, например:
Type
TNewClass = class
FCod: Integer;
FCh: Char;
FObjField: TList;
...
end;
Каждый объект получает уникальный набор полей, но общий для всех объектов данного класса набор методов и свойств. Фундаментальный принцип инкапсуляции требует обращаться к полям только с помощью методов и свойств класса. Однако в Delphi разрешается обращаться к полям и напрямую:
Var
NewClass: TNewClass;
Begin
...
FCod:=0;
FCh:=‘с’;
...
End;
Класс-потомок получает все поля всех своих предков и может дополнять их своими, но он не может переопределять или удалять поля предка. Таким образом, чем ниже в дереве иерархии располагается класс, тем больше данных получают в свое распоряжение их объекты.
Свойства
Свойства объектов аналогичны свойствам, которые мы наблюдаем у обычных предметов. Значения свойств можно читать и устанавливать. Например, панель имеет свойство «цвет». Значение этого свойства хранится в одном из полей. Чтобы узнать цвет, надо прочитать значение соответствующего поля; чтобы изменить цвет, надо вызвать метод, который перерисует панель в соответствии с новым значением поля, содержащего цвет панели. Таким образом, свойства – это специальный механизм классов, реализующий доступ к полям. Обычно свойство связано с некоторым полем и указывает те методы класса, которые должны использоваться при записи данных в это поле и при чтении значений из него. Описание свойства начинается со слова property, при этом тип свойства и соответствующего поля должны быть одинаковыми.
property Cod: integer read Fcod write FCod;
property Ch: сhar read FCh write FCh;
property PercentCritical: integer read FpercentCritical write SetPercentCritical;
После слова read указывается поле или метод, к которому происходит обращение при чтении значения свойства, а после слова write – поле или метод, к которому происходит обращение при записи свойства. Атрибуты read и write называют спецификаторами доступа. Если один из них опущен, то свойство можно только читать (задан read) или только записывать (задан write). Метод чтения поля – это всегда функция, возвращающая значение того же типа, что и свойство. Метод записи свойства – это всегда процедура, принимающая параметр того же типа, что и тип свойства. Один и тот же метод может использоваться для получения (установки) значений нескольких свойств одного типа. В этом случае каждому свойству назначается целочисленный индекс, который передаётся в метод первым параметром.
При работе с объектом свойства выглядят как поля: они принимают значения и участвуют в выражениях. Но в отличие от полей, свойства не занимают места в памяти, а операции их чтения и записи ассоциируются с обычными полями и методами. Так как свойства не имеют адреса в памяти, к ним нельзя применить операцию @ и их нельзя передавать в качестве параметров-переменных (Var) процедур и функций.
Технология ООП в Delphi предписывает избегать прямого обращения к полям, создавая вместо этого свойства. Это упорядочивает работу с объектами, изолируя их данные от непосредственной модификации. Для программиста свойства имеют первостепенное значение. Чтобы понять суть и назначение объекта, надо знать его свойства, реже методы и очень редко – поля (объект сам знает, что с ними делать).
Обычно свойство связано с некоторым полем, но это не обязательно. Фактически свойство описывает один или два метода, которые осуществляют некоторые действия над данными того же типа, что и поле. Кроме обычных свойств у объектов существуют свойства-массивы (array properties). Свойство - массив – это индексированное множество свойств.
Методы
Метод (правило) представляет собой процедуру или функцию, определенную в рамках класса, и используемую для выполнения действий над полями. В разделе interface содержится объявление методов (при описании класса), а в разделе implementation записывается программный код. В отличие от обычных процедур и функций заголовки методов должны иметь составные имена, содержащие наименование классов. Внутри методов обращения к полям и другим методам выполняется как к обычным переменным и подпрограммам, без уточнения объекта. Следуя логике объектно-ориентированного программирования, все мыслимые действия над полями объекта необходимо определять в виде правил – процедур и функций. Именно это в конечном итоге обеспечивает простоту и универсальность ООП, так как описание каждого класса становится функционально завершённым на соответствующем уровне иерархии. Описание класса получается громоздким, но очень удобным для дальнейшего использования.
Наиболее полно стараются описать классы, расположенные на верхних уровнях иерархии. При этом можно не заботиться о том, что какой-либо метод не будет использован, так как код методов, к которым нет обращения в программе, компилятор не включает в exe-файл.
Type
TMyClass = class
Function MyFunc (aPar: Integer): Integer;
Procedure MyProc;
End;
Var
aObject: TMyClass;
...
Begin
...
aObject.MyProc;
...
end;
Методы класса могут перекрываться в потомках. Например:
Type
TParentClass = class
Procedure DoWork;
End;
TChildClass = Class (TParentClass)
Procedure DoWork;
End;
Потомки обоих классов могут выполнять сходную по названию процедуру DoWork, но, в общем случае, будут это делать по-разному. Такое замещение методов называется статическим, так как реализуется компилятором. В состав любого класса входят два специальных метода – конструктор и деструктор. У класса TObject эти методы называются Create и Destroy, так же они называются в подавляющем большинстве его потомков. Обращение к конструктору должно предварять любое обращение к полям и некоторым методам объекта.
DiskGauge:=TDiskGauge.Create;
Конструктор создаёт объект. Создание объекта включает выделение памяти и инициализацию полей. Распределив объект в динамической памяти, конструктор помещает адрес этой области памяти в переменную Self, которая автоматически объявляется в классе. Деструктор разрушает объект: очищает поля и удаляет объект из кучи (освобождает память):
DiskGauge.Destroy;
После вызова деструктора обращаться к полям и методам объекта нельзя.
Так как действия, выполняемые при создании и разрушении разных объектов, могут быть специфичными, то Delphi позволяет переопределить стандартные конструктор Create и деструктор Destroy. Можно даже определить несколько конструкторов и деструкторов, выполняющих свою работу разными способами. Объявление конструкторов и деструкторов аналогично объявлению обычных процедур, только вместо слова procedure используются constructor и destructor.
Конструктор может иметь параметры, через которые передаются исходные значения полей. Конструктор может применяться к классу или объекту. При применении конструктора к классу выполняются действия:
· выделяется в памяти место под объект;
· выделенная память заполняется. Поля, содержащие указатели и объекты, получают значение nil. Числовые поля заполняются нулями.
Строки задаются пустыми;
· выполняются действия, определяемые конструктором;
· ссылка на созданный объект возвращается в качестве значения конструктора. Тип возвращаемого значения совпадает с типом класса, использованного при вызове.
При применении конструктора к объекту новый объект не создаётся, происходит переинициализация полей существующего. В этом случае конструктор не возвращает никакого значения.
Деструктор уничтожает объект, к которому применяется: выполняется заданный программный код деинициализации, освобождается занимаемая объектом динамическая память. В теле деструктора должны уничтожаться встроенные объекты и динамические данные, созданные конструктором. Вызов деструктора для несуществующего объекта недопустим, если это сделать, то произойдёт ошибка. Чтобы освободить программиста от необходимости контролировать наличие объекта и его состояние (равен или нет nil), ввели предопределённый метод Free, который следует вызывать вместо деструктора. Метод Free сам вызывает Destroy, но только если значение объекта не равно nil.
DiskGauge.free;
Большинство конструкторов реализуют некоторые действия, необходимые для правильной работы объекта. Поэтому в конструкторе класса-потомка надо, сначала вызвать конструктор родителя, а потом задать дополнительные действия. Вызов любого перекрытого метода родительского класса выполняется с помощью зарезервированного слова inherited.
Constructor TMyClass.create(mmm:byte);
begin
inherited Create;
intfield:=mmm;
end;
Метод, объявленный в классе, в зависимости от вида может вызываться разными способами. Вид метода задаётся служебным словом (модификатором), которое указывается в описании класса после заголовка метода и отделяется от него точкой с запятой. Основные типы методов:
· abstract – абстрактный;
· virtual – виртуальный;
· dynamic – динамический;
· override – перекрывающий;
· message – обработки сообщения.
Методы принято разделять на обычные (статические) и динамические. При обращении к обычному методу компилятор точно знает класс, которому данный метод принадлежит.
В Delphi чаще используется динамическое замещение методов на этапе выполнения программы. Для этого метод, замещаемый в родительском классе, должен объявляться как динамический (с директивой dynamic) или виртуальный (virtual). В производных классах (потомках) виртуальный и динамический методы перекрываются с использованием слова override. Перекрывающий метод должен иметь точно такой же список параметров, что и перекрываемый. Суть динамического замещения методов в том, что они вызываются по фактическому типу экземпляра. Работа виртуальных методов основана на механизме позднего связывания, в отличие от раннего связывания, характерного для обычных методов. Позднее связывание основано на вычислении адреса вызываемого метода при выполнении программы. Адрес вычисляется по хранящемуся в каждом объекте описателю типа. Виртуальные методы позволяют в полной мере реализовать идею полиморфизма.
Разница между виртуальным и динамическим методами заключается в особенностях создаваемых таблиц и, как следствие, в разной скорости работы. Встретив метод, объявленный как виртуальный или динамический, компилятор создаёт таблицу DMT (Dinamic Method Table) или VMT (Virtual Method Table) и помещает в неё адреса точек входа соответственно динамического или виртуального методов. При каждом обращении к замещаемому методу компилятор вставляет код, позволяющий извлечь адрес точки входа в подпрограмму из той или иной таблицы. Когда в классе-потомке встречается метод, объявленный с директивой override, компилятор создаст код, который на этапе прогона программы поместит в родительскую таблицу точку входа метода класса-потомка, что позволит родителю выполнить нужное действие с помощью нового метода. Таблица динамических методов содержит адреса только тех методов, которые объявлены как dynamic в данном классе, в то время как таблица VMT содержит адреса виртуальных методов не только данного метода, но и всех его родителей. Значительно большая по размеру таблица VMT обеспечивает более быстрый поиск. При использовании динамического метода программа сначала просматривает таблицу DMT у объекта, а затем у его родительского класса и так далее, пока не будет найдена нужная точка входа.
При построении иерархии классов часто возникает ситуация, когда работа виртуального метода в базовом классе неизвестна и наполняется содержанием только в потомках. В этом случае метод объявляется абстрактным. После слова virtual записывается директива abstract, что исключает необходимость написания кода для виртуального метода.
Абстрактный метод подразумевает конкретное действие, а не способ его реализации. Реализацию такие методы получают в наследниках. Классы, содержащие абстрактные методы, называются абстрактными. Объекты абстрактных классов никогда не создаются. Для использования абстрактных классов в библиотеку классов включаются потомки. Например, для разных геометрических фигур можно определить единые методы show, hide, moveto и абстрактный метод draw. Метод draw для каждой фигуры реализуется по-разному.
Управление доступом к классу
Существует три типа пользователей класса:
· сам класс (методы класса могут обращаться к другим методам и данным класса);
· обычные пользователи, то есть программы пользователя;
· производные классы (методы производного класса могут обращаться к методам или данным базового класса).
Каждый пользователь обладает разными привилегиями доступа. Уровни доступа задаются ключевыми словами private, public, protected. Приватные члены класса, объявленные в секции private, имеют самую ограниченную область действия. Они доступны только внутри методов данного класса и подпрограмм, находящихся в том же модуле. Элемент, объявленный как private, недоступен даже ближайшим потомкам класса, если они размещены в других модулях. Обратите внимание, что приватные данные видимы, но недоступны. Такой контроль введен для предотвращения случайного доступа к данным или внутренним функциям, то есть в целях уменьшения ошибок при разработке программ, но не для предотвращения «взлома»
Ко всему, что объявлено в секции public, разрешен неограниченный доступ. В частности, можно все содержимое класса объявить общедоступным и манипулировать им, как заблагорассудится. При определении класса часть методов, свойств и полей можно скрыть от пользователя, но сделать доступными для производных классов, поместив их в секцию с ключевым словом protected. Элементы описания, размещённые в защищённой секции доступны только методам самого класса и любым его потомкам, независимо от того, находятся они в том же модуле, или нет.
Кроме перечисленных выше секций есть ещё одна – published. Правила видимости у этой секции такие же, как у public. Особенность в том, что для элементов, помещённых в эту секцию, генерируется информация, позволяющая превращать их в компоненты. Те свойства, которые должны быть доступны в Инспекторе объектов, обязательно надо поместить в эту секцию. Секция published используется при разработке компонентов. По умолчанию (без указания типа секции) секция считается объявленной как published. Такая секция помещается в самом начале объявления класса любой формы и продолжается до первой объявленной секции, в неё Delphi помещает описания расположенных на форме компонентов.

This site was made on Tilda — a website builder that helps to create a website without any code
Create a website