Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Рабочая тетрадь по ООП.doc
Скачиваний:
6
Добавлен:
09.11.2019
Размер:
320 Кб
Скачать

Лекция 2. Класс и ключевые понятия

Основные определения лекции

Примечания

КЛАССЫ

Класс –структура, включающая в себя описания данных и описание процедур и функций, обрабатывающих эти данные (например, группа).

Объект – представитель (экземпляр) класса (например, студент этой группы).

Класс – это обобщенное (абстрактное) описание множества однотипных объектов.

Класс обычно описывает сущность, абстракцию, моделируемую в программе.

Класс описывается в секции INTERFACE модуля.

Класс – это тип объекта.

Объект – это экземпляр определенного класса.

Поле – это переменная , входящая в состав объекта (или поля экземпляра, член экземпляра, переменная экземпляра).

Свойство – это интерфейс доступа к полю. Со свойством связаны спецификаторы доступа, определяющие что происходит при чтении или записи значения в поле свойства.

Метод – это подпрограмма, ассоциированная с классом.

Заголовки методов играют роль предварительных объявлений.

Сам программный код методов помещается в секции IMPLEMENTATION.

Заголовки методов при этом имеют уточненные имена, т.е. содержат в своем имени и имя класса.

Внутри метода обращение к полям и другим методам выполняется как к обычным переменным и подпрограммам без уточнения экземпляра объекта.

Чтобы перейти от описания класса к экземпляру класса – объекту, следует выполнить соответствующее объявление в секции var.

Объекты - динамические данные, т.е. распределяются в «куче».

Переменная – это ссылка на экземпляр объекта.

Для конструирования объекта класса необходимо записать оператор:

Student := TPerson.Create;

Create – конструктор объекта. Он всегда присутствует в классе и служит для создания и инициализации экземпляров.

В «куче» выделяется место только для полей объекта (т.к. каждый экземпляр имеет свои данные).

Методы помещаются в область кода программы (т.к. все экземпляры классы имеют общие методы).

При создании объекта выполняются действия:

в динамической памяти выделяется место для нового объекта,

выделенная память «обнуляется»( числовые поля и поля порядкового типа приобретают значения нуль, строковые поля становятся пустыми, а поля, содержащие указатели и объекты, получают значение nil);

выполняются заданные действия конструктора;

ссылка на заданный объект возвращается в качестве значения конструктора; тип возвращаемого значения совпадает с типом класса.

После создания объекта его можно использовать в программе.

Доступ к полям и методам происходит с помощью уточненных имен :

<имя переменной>.< имя поля или метода>;

professor.FName := 'Иванов';

Чтобы выполнить метод, надо выполнить инструкцию

professor.Print;

Если объект становится не нужен в программе, он должен быть удален вызовом специального метода Destroy, например: Professor.Destroy;

Destroy – деструктор объекта, он присутствует в классе наряду с конструктором и служит для удаления объекта из динамической памяти.

После вызова деструктора переменная становится несвязанной и не может использоваться для доступа к полям и методам несуществующего объекта.

Если не известно, удален объект или нет, лучше вызывать метод Free, который автоматически вызывает метод Destroy для не удаленного объекта и не генерирует ошибку в случае удаленного объекта:

Professor. Free;

Destroy и Create являются стандартными методами.

Они предопределенны в классе TObject – предка всех классов, но можно и создать конструкторы и деструкторы самим.

Обычно их создают для выполнения каких-либо действий.

Конструкторы и деструкторы

- являются особой разновидностью методов, которые можно описать в классе.

Конструкторы создают, а деструкторы – разрушают объекты.

Создание объекта включает выделение памяти под экземпляр и инициализацию его полей, а разрушение – очистку полей и освобождение памяти.

Очевидно, что указанные действия специфичны для каждого конкретного класса. По этой причине Object Pascal позволяет переопределить стандартные конструктор Create и деструктор Destroy для выполнения любых полезных действий.

Объявление конструкторов и деструкторов аналогично объявлению методов:

Возможная реализация конструктора:

constructor TPerson.Create;

begin

FName := '';

FAdres := '';

end;

СВОЙСТВА ОБЪЕКТА

В Object Pascal ограничение доступа к полям объекта реализуется при помощи свойств объекта.

Свойство объекта характеризуется полем, хранящим значение свойства, и двумя методами, обеспечивающими доступ к полю свойства.

Метод установки значения свойства называется методом записи свойства (write),

метод получения значения свойства называют методом чтения свойства (read).

Метод чтения значения поля свойства обычно обозначают Get<имя поля свойства>: GetColor;

Метод возвращает значение, т.е. его оформляют в виде функции.

Метод записи значения в поле свойства обозначают Set<имя поля свойства> и оформляют в виде процедуры:

SetColor(Red);

Можно записать наш класс следующим образом:

Type

TPerson= Class

FName : string;

FAdres : string;

Constructor Create (Name : string);

Function GetName : string;

Property Name : string read GetName;

Function GetAdres : string;

Procedure SetAdres (NewAdres : string);

Property Adres : string

read GetAdres write SetAdres;

end;

В программе на методы свойства можно наложить некоторые дополнительные задачи (проверить корректность присваиваемых свойству значений, установить значения и др.).

Оформление поля как свойства позволяет ограничить доступ к его значению, например, разрешить только чтение.

В этом случае в описании свойства надо указывать только метод чтения.

Попытка присвоения значения свойству вызовет ошибку при компиляции.

В нашем примере свойство Name доступно только для чтения, свойство Adres – для чтения и записи.

Установить значения свойства, защищенного от записи, можно во время инициализации объекта.

Инструкции программы, обеспечивающие создание объекта и установку его свойств, могут быть такими:

student := TPerson.Create ('Иванов');

Для установления значения свойства можно написать инструкцию применения метода:

student.SetAdres ('Пермь'); – метод свойства SetAdres применен к объекту.

Но можно записать простую команду присвоения:

student.Adres := 'Пермь'; которую транслятор перетранслирует в выше описанную инструкцию вызова метода свойства.

Реализация принципов ООП в Delpfi

Инкапсуляция:

поля и методы объединены в одной структуре – классе.

Поля класса недоступны напрямую.

Чтение и обновление реализуется через вызовы соответствующих методов.

Принцип инкапсуляции гласит, что поля должны быть описаны в приватной части класса (об этом позднее) и доступ к ним через методы и свойства:

Type

TMyClass = Class

private

FField : MyType;

function…….

published

property Field : MyType read …….

end;

2. Наследование.

Концепция ООП предполагает возможность определять новые кассы посредством добавления полей, свойств и методов к уже существующим классам.

Такой механизм получения новых классов называется наследованием или порождением.

При этом новый, порожденный, класс (потомок) наследует свойства и методы своего базового, родительского класса.

В объявлении класса потомка указывается класс родителя.

Например, будем рассматривать какие-то отделы организации (или кафедры) и сотрудников в нем.

Для описания класса Сотрудник тоже необходимы поля: имя, адрес и методы, т.е. тоже, что и имеем в классе TPerson.

А зачем снова повторяться?

Объявим новый класс сотрудник (sotr), который может быть порожден от рассмотренного выше класса TPerson путем добавления недостающего поля FKaf (отдел, кафедра).

Объявление класса TSotr в этом случае может выглядеть так:

Type

TSotr = Class (TPerson)

FKaf : String[10]; {поле }

Constructor Create (Name, Dep : String;);

End;

Если предок не указан, то по умолчанию им является класс TObject.

Класс TSotr имеет свой собственный конструктор, который обеспечивает инициализацию класса родителя и своих полей:

Constructor TSotr.Create (Name , Dep : String;);

Begin

Inherited Create (Name);

FKaf := Dep;

End;

Как видно из примера, в наследнике можно перекрыть метод предка, указав перед именем метода зарезервированное слово INHERITED.

После создания объекта производного класса можно записать:

Var

Engineer : TSotr;

В программе можно использовать поля и методы родительского класса:

Engineer := TSotr.Create (' иванов ', ' алгебра ');

Engineer.Adres := ' Пермь ';

Первая инструкция создает объект типа TSotr. Вторая инструкция устанавливает значение свойства, которое относится к родительскому классу.

3. Полиморфизм.

Мы говорили, что полиморфизм представляет собой свойство различных объектов выполнять одно и тоже действие по-своему.

Или

Полиморфизм — это возможность использовать одинаковые имена для методов, входящих в различные классы.

Концепция полиморфизма состоит в том, что при применении метода к объекту используется именно тот метод, который соответствует классу объекта.

Пусть определены два класса, один из которых является базовым для другого.

TPerson = Class {родительский класс}

FName: string; {поле имя }

constructor Create (Name: string) ;

procedure Print;

end;

TStud = Class (TPerson) {порожденный класс}

FGr : integer; {поле- номер группы }

constructor Create (Name: string; gru: integer) ;

procedure Print;

end;

В каждом из классов определен метод Print.

В базовом классе при помощи директивы VIRTUAL метод Print объявлен виртуальным.

Объявление метода виртуальным дает возможность дочернему классу заместить виртуальный метод своим собственным.

В дочернем классе определен свой метод Print, который замещает соответствующий метод родительского класса.

Метод порожденного класса, который замещает виртуальный метод родительского класса, помечается директивой OVERRIDE.

Замена метода базового класса методом дочернего класса называется Перекрытием атрибутов в наследниках (переопределением методов).

Определение метода Print родительского класса:

procedure TPerson.Print;

begin

{может быть и пустым, в этом случае метод TPerson.Print помечается дополнительно!!! директивой ABSTRACT;}

end;

procedure TStud .Print;

begin

вывод (FName+' rpуппа '+IntToStr (FGr) ) ;

end;

Виртуальные и динамические методы

В механизме наследования можно условно выделить три основных момента:

наследование полей,

наследование свойства,

наследование методов.

Любой порожденный класс наследует от родительского все поля данных.

Наследование свойств и методов имеет свои особенности.

Свойство базового класса можно перекрыть в производном классе, чтобы добавить ему новый атрибут доступа или связать с другим полем или методом.

Метод базового класса также можно перекрыть в производном классе, например, чтобы изменить логику его работы (метод TPerson.Print перекрыт методам TStud.Print).

Все методы имеют одну общую черту – все они статические. Для статических методов характерно раннее связывание.

При обращении к статическому методу компилятор точно знает класс, которому принадлежит данный метод.

Работа виртуальных методов (помечены директивой VIRTUAL;) основана на механизме позднего связывания.

Позднее связывание основано на вычислении адреса вызываемого метода при выполнении программы.

Метод вычисляется по хранящемуся в каждом объекте описателю типа

При построении иерархии часто возникает ситуация, когда работа виртуального метода в базовом классе неизвестна и наполняется содержанием только в наследниках.

Тогда его помечают директивой abstract.

Директива abstract записывается после virtual и исключает необходимость написания кода виртуального метода для данного класса в секции IMPLEMENTATION.

Разновидностью виртуальных методов являются так называемые динамические методы.

При их объявлении записывается ключевое слово dynamic.

Семантически динамические и виртуальные методы идентичны.

Различие состоит в механизме их вызова.

Методы виртуальные вызываются максимально быстро, но платой за это является большой размер системных таблиц, с помощью которых происходит их диспетчеризация.

Динамические методы вызываются дольше, но таблицы имеют более компактный вид, что экономит память.

Видимость атрибутов объекта

Программист имеет возможность ограничить видимость атрибутов класса.

Для этого служат директивы:

private,

protected,

public,

published.

Private. Все, что объявлено в этой секции, недоступно за пределами модуля.

Эта секция позволяет скрывать те поля и методы, которые относятся к так называемым особенностям реализациям.

Public. Поля, методы и свойства, объявленные в этой секции, не имеют никаких ограничений на использование, т.е. всегда видны за пределами модуля.

Все что помещается в этой секции составляет программный интерфейс класса

Protected. Поля, методы и свойства, объявленные в этой секции, видны за пределами модуля только потомкам данного класса; остальным частям программы они не видны.

В эту часть обычно помещают виртуальные методы чтения и записи свойств.

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

Реализуем рассмотренные классы в Delphi:

Классы можно описать в отдельном модуле и затем вызвать командой Uses MyModula;

либо - в том модуле, где вы работаете (что и сделано в нашем примере).

Программа:

Объектно-ориентированное программирование

Синтаксис:

TYPE

<имя_класса> = CLASS

<имя поля_1> : <тип>;

............

<имя поля _n> : <тип>;

<метод_1>;

.............

<метод_n>;

property ….;

END;

Пример:

Разработать класс: персона, имеющая имя и адрес, распечатать эти данные

INTERFACE

………………

TYPE

TPerson = class

FName : string [15]; {поле}

FAdres : string [35]; {поле}

procedure Print; {метод распечатки данных }

end;

Пример:

IMPLEMENTATION

procedure TPerson.Print;

begin

вывод (' Имя: ', FName, ' Адрес: ', FAdres);

end;

Var

student : TPerson;

professor : TPerson;

где student, professor – объекты класса TPerson.

type

TPerson = Class

FName : string[15];

FAdres : string[35];

procedure Print;

constructor Create;

end;

Синтаксис:

Property <имя свойства> : <тип свойства> read <метод> write <метод>;

Например:

Constructor TPerson.Create (Name : string);

begin

FName := Name; {в поле записывается значение свойства}

Adres :=' '; {конструктор создает и инициализирует значение свойства}

end;

{метод получения значения свойства}

Function TPerson.GetName;

begin

Result := FName;

end;

{метод получения значения свойства Adres}

Function TPerson.GetAdres;

begin

Result := FAdres;

end;

{метод изменения значения свойства Adres}

Procedure TPerson.SetAdres (NewAdres : string);

begin

if FAdres = ' ' then FAdres := NewAdres;

end;

unit Unit1;

interface

uses …;

type

TForm1 = class(TForm)

Label1: TLabel;

Edit1: TEdit;

Label2: TLabel;

Edit2: TEdit;

Label3: TLabel;

Edit3: TEdit;

Label4: TLabel;

Edit4: TEdit;

Label5: TLabel;

Edit5: TEdit;

Button1: TButton;

BitBtn1: TBitBtn;

procedure Button1Click(Sender: TObject);

procedure FormActivate(Sender: TObject);

end;

TPerson = Class // базовый класс

FName : string;

FAdres : string;

procedure Print; virtual;

end;

TStud = Class(TPerson) //наследник

FGr : integer;

procedure Print; override;

end;

var

Form1: TForm1;

p :TPerson; //объявление переменных

s : TStud;

implementation

{$R *.dfm}

procedure TPerson.Print;

begin

if Fname <> ' ' then

ShowMessage('сотрудник ' + Fname + ' ' + FAdres);

end;

procedure TStud.Print;

begin

if Fname <> ' ' then

ShowMessage('Студент ' + Fname + ' ' + FAdres + ' ' + IntToStr(Fgr));

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

p := TPerson.Create;

s := TStud.Create;

p.FName:= Edit1.Text;

p.FAdres:= Edit2.Text;

s.FName :=Edit3.Text;

s.FAdres :=Edit4.Text;

s.FGr := StrToInt(Edit5.Text);

s.print;

p.Print;

end;

procedure TForm1.FormActivate(Sender: TObject);

begin

edit1.Text := '';

edit2.Text := '';

edit3.Text := '';

edit4.Text := '';

edit5.Text := IntToStr(0);

end;

end.