Компания ALT Linux
Опубликован: 10.04.2015 | Доступ: свободный | Студентов: 762 / 0 | Длительность: 14:03:00
Специальности: Программист, Преподаватель
Лекция 9:

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

< Лекция 8 || Лекция 9: 12345 || Лекция 10 >

Эта глава посвящена изучению объектно-ориентированного программирования (ООП). ООП — это методика разработки программ, в основе которой лежит понятие объекта, как некоторой структуры, описывающей объект реального мира, его поведение и взаимодействие с другими объектами.

9.1 Основные понятия

Основой объектно-ориентированного программирования является объект. Объект состоит из трёх основных частей:

  1. Имя (например, автомобиль);
  2. Состояние, или переменные состояния (например, марка автомобиля, цвет, масса, число мест и т. д.);
  3. Методы, или операции, которые выполняют некоторые действия над объектами и определяют, как объект взаимодействует с окружающим миром.

Для работы с объектами во FreePascal введено понятие класса. Класс — сложная структура, включающая в себя описание данных, процедуры и функции, которые могут быть выполнены над объектом.

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

Объектно-ориентированное программирование (ООП) представляет собой технологию разработки программ с использованием объектов. В объектноори-ентированных языках есть три основных понятия: инкапсуляция, наследование и полиморфизм. Инкапсуляцией называется объединение в классе данных и подпрограмм для их обработки. Наследование — это когда любой класс может быть порождён другим классом. Порождённый класс (наследник) автоматически наследует все поля, методы, свойства и события. Полиморфизм позволяет использовать одинаковые имена для методов, входящих в различные классы.

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

type

<название класса> = class (<имя класса родителя>)

<поля и методы класса>

private

<поля и методы, доступные только в пределах модуля>

protected

<поля и методы, доступные только в классах-потомках>

public

<поля и методы, доступные из других модулей>

published

<поля и методы, видимые в инспекторе объектов>

end;

В качестве имени класса можно использовать любой допустимый в FreePascal идентификатор. Имя класса родителя — имя класса, наследником которого является данный класс, это необязательный параметр, если он не указывается, то это означает, что данный класс является наследником общего из предопределённого класса TObject.

Структуры отличаются от классов тем, что поля структуры доступны всегда. При использовании классов могут быть члены, доступные везде — публичные (описатель public), и приватные (описатель private ), доступ к которым возможен только с помощью публичных методов. Это также относится и к методам класса. Поля, свойства и методы секции public не имеют ограничений на видимость. Они доступны из других функций и методов объектов как в данном модуле, так и во всех прочих, ссылающихся на него. При обращении к публичным полям вне класса используется оператор "." (точка).

Поля, свойства и методы, находящиеся в секции private, доступны только в методах класса и в функциях, содержащихся в том же модуле, что и описываемый класс. Это позволяет полностью скрыть детали внутренней реализации класса. Вызов приватных методов осуществляется из публичных.

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

Защищенный (protected ) — это раздел, содержащий поля и методы, которые доступны внутри класса, а также любым его классам-потомкам, в том числе и в других модулях.

Поля и методы, описанные до указания имени секции, являются публичными (public).

При программировании с использованием классов, программист должен решить, какие члены и методы должны быть объявлены публичными, а какие приватными. Общим принципом является следующее: "Чем меньше публичных данных о классе используется в программе, тем лучше". Уменьшение количества публичных членов и методов позволит минимизировать количество ошибок.

Поля могут быть любого типа, в том числе и классами. Объявление полей осуществляется так же, как и объявление обычных переменных:

поле1 : тип_данных;

поле2 : тип_данных;

...

Методы в классе объявляются так же, как и обычные подпрограммы:

function метод1 (список параметров ) : тип результата;

procedure метод2 (список параметров );

Описание процедур и функций, реализующих методы, помещается после слова implementation того модуля, где объявлен класс, и выглядит так:

function имя_класса.метод1(список параметров ) : тип результата;

begin

тело функции;

end;

procedure имя_класса.метод2(список параметров );

begin

тело функции;

end;

Объявление переменной типа class называется созданием (инициализацией) объекта (экземпляра класса). Экземпляр класса объявляется в блоке описания переменных:

var имя_переменной : имя_класса;

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

имя_переменной.поле1:=выражение;

имя_переменной.метод1(список параметров );

...

Также можно использовать оператор With:

With имя_переменной do

begin

поле1:=выражение;

метод1(список параметров );

...

end;

В Free Pascal имеется большое количество классов, с помощью которых описывается форма приложения и её компоненты (кнопки, поля, флажки и т. п.). В процессе конструирования формы в текст программы автоматически добавляются программные объекты. Например, при добавлении на форму компонента формируется описание класса для этого компонента, а при создании подпрограмм обработки событий в описание класса добавляется объявление методов. Рассмотрим это на примере проекта с формой, на которой есть кнопка Button1.

unit Unit1;
interface
uses
Classes, SysUtils, LResources, Forms, Controls, Graphics,
Dialogs, StdCtrls;
type
{ TForm1 }
//объявление класса формы TForm1
TForm1 = class (TForm)
//объявление компонента кнопки Button1
Button1 : TButton;
//объявление метода обработки события -//щелчка по кнопке Button1
procedure Button1Click ( Sender : TObject );
private
{ private declarations }
public
{ public declarations }
end;
var
//описание переменной класса формы TForm1
	Form1 : TForm1;
implementation
{ TForm1 }
//описание метода обработки события - щелчка по кнопке Button1
procedure TForm1. Button1Click ( Sender : TObject );
begin
	//Текст процедуры обработки события
end;
initialization
{$I unit1.lrs}
end.

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

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

constructor Create;

Описывают конструктор так же, как и другие методы, после ключевого слова implemention того модуля, в котором объявлен класс.

constructor имя_класса. Create;

begin

поле1:=выражение1;

поле2:=выражение2;

...

inherited Create;

end;

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

Деструктор — это специальный метод, уничтожающий объект и освобождающий занимаемую им память. Объявляется деструктор следующим образом:

destructor Destroy;

Если в программе какой-либо объект больше не используется, то оператор

имя_переменной_типа_класс. free;

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

Рассмотрим всё описанное на примере класса "комплексное число"1С комплексными числами мы уже сталкивались в предыдущих главах, подробнее о работе с ними можно прочитать на странице http://kvant.mccme.ru./1982/03/komplesnye_chisla.htm .. Назовём этот класс Tcomplex. В нём будут члены класса: x — действительная часть комплексного числа — и y — мнимая часть комплексного числа. Также в классе будут методы:

  • конструктор Create, который будет записывать в действительную и мнимую части значение 0;
  • Modul() — функция вычисления модуля комплексного числа;
  • Argument() — функция вычисления аргумента комплексного числа;
  • ComplexToStr() — функция, представляющая комплексное число в виде строки для вывода.

Создадим новый проект, на форму поместим кнопку Button1, два поля — Edit1 и Edit2 — для ввода действительной и мнимой частей, для вывода результатов разместим компонент Memo1. При щелчке по кнопке будет создаваться экземпляр класса "Комплексное число", затем будет вычисляться его модуль и аргумент. В компонент Memo1 выведем результаты: число в алгебраической форме, его аргумент и модуль. Ниже приведём текст модуля с комментариями, который демонстрирует работу с этим классом.

unit Unit1;
{$mode objfpc}{$H+}
interface
uses
	Classes, SysUtils, LResources, Forms, Controls, Graphics,
	Dialogs, StdCtrls;
type
	{ TForm1 }
	TForm1 = class (TForm)
	Button1 : TButton;
	Edit1 : TEdit;
	Edit2 : TEdit;
	Label1 : TLabel;
	Label2 : TLabel;
	Label3 : TLabel;
	Memo1 : TMemo;
	procedure Button1Click ( Sender : TObject );
private
	{ private declarations }
public
	{ public declarations }
end;
type
//описание класса - комплексное число
	TComplex = class
	private
		x : real; //действительная часть
		y : real; //мнимая часть
	public
		constructor Create; //конструктор
		function Modul ( ) : real; //метод вычисления модуля
		function Argument ( ) : real; //метод вычисления аргумента
		//метод записи комплексного числа в виде строки
		function ComplexToStr ( ) : String;
	end;
var
	Form1 : TForm1;
//объявление переменной типа класс "комплексное число"
	chislo : TComplex;
implementation
//описание конструктора
constructor TComplex. Create;
begin
	x : = 0; y : = 0;
//Вызов родительского конструктора
	inherited Create;
end;
//Описание метода вычисления
//модуля комплексного числа.
function TComplex. Modul ( ) : real;
begin
	modul:= sqrt ( x * x+y * y );
end;
//Описание метода вычисления
//аргумента комплексного числа.
function TComplex. Argument ( ) : real;
begin
	argument := arctan ( y/x ) * 180/ pi;
end;
//Описание метода записи комплексного
//числа в виде строки.
function TComplex. ComplexToStr ( ) : String;
begin
	if y>=0 then
		ComplexToStr := FloatToStrF ( x, ffFixed,5,2)+ ’+ ’ +
FloatTostrF ( y, ffFixed,5,2)+ ’ i ’
	else
ComplexToStr := FloatTostrF ( x, ffFixed,5,2)+
FloatTostrF ( y, ffFixed,5,2)+ ’ i ’
end;
{Обработчик кнопки: создание экземпляра класса "Комплексное число }
{вычисление его модуля и аргумента, вывод числа в алгебраической форме,}
{его аргумента и модуля.}
procedure TForm1. Button1Click ( Sender : TObject );
var Str1 : String;
begin
//создание объекта (экземпляра класса) типа "комплексное число"
	chislo :=TComplex. Create;
//ввод действительной и мнимой частей комплексного числа
	chislo. x:= StrToFloat ( Edit1. Text );
	chislo. y:= StrToFloat ( Edit2. Text );
	Str1 := ’ Kompleksnoe   chislo   ’+c h i s l o. ComplexToStr ( );
//вывод на форму в поле Memo1 построчно комплексного числа,
	Memo1. Lines. Add( Str1 );
//его модуля
	Str1 := ’ Modul  chisla   ’+
	FloatToStrF ( chislo. Modul ( ), ffFixed, 5, 2 );
	Memo1. Lines. Add( Str1 );
//и аргумента
	Str1 := ’ Argument  chisla  ’+
	FloatToStrF ( chislo. Argument ( ), ffFixed, 5, 2 );
	Memo1. Lines. Add( Str1 );
//уничтожение объекта
	chislo. Free;
end;
initialization
	{$I unit1.lrs}
end.

Результат работы программы приведён на рис. 9.1.

Результаты работы программы работы с классом "Комплексное число"

Рис. 9.1. Результаты работы программы работы с классом "Комплексное число"

В этом примере был написан конструктор для класса "комплексное число" без параметров. В FreePascal можно писать конструктор с параметрами, который принимает входные значения и инициализирует поля класса этими значениями. Перепишем предыдущий пример следующим образом. Действительную и мнимую часть будем считывать из полей ввода формы и передавать в конструктор для инициализации объекта типа "комплексное число". Листинг программы приведён ниже.

unit Unit1;
{$mode objfpc}{$H+}
interface
uses
	Classes, SysUtils, LResources, Forms, Controls, Graphics,
	Dialogs, StdCtrls;
type
	{ TForm1 }
	TForm1 = class (TForm)
	Button1 : TButton;
	Edit1 : TEdit;
	Edit2 : TEdit;
	Label1 : TLabel;
	Label2 : TLabel;
	Label3 : TLabel;
	Memo1 : TMemo;
	procedure Button1Click ( Sender : TObject );
	procedure Memo1Change ( Sender : TObject );
private
	{ private declarations }
public
	{ public declarations }
end;
type
TComplex = class
	private
	x, y : real;
	public
//объявление конструктора
		constructor Create ( a, b : real );
		function Modul ( ) : real;
		function Argument ( ) : real;
		function ComplexToStr ( ) : String;
end;
var
	Form1 : TForm1;
	chislo : TComplex;
implementation
//Конструктор, который получает в качестве
//входных параметров два вещественных числа и записывает их
//в действительную и мнимую часть комплексного числа
constructor TComplex. Create ( a, b : real );
begin
	x:=a; y:=b;
	inherited Create;
end;
function TComplex. Modul ( ) : real;
begin
	modul:= sqrt ( x * x+y * y );
end;
function TComplex. Argument ( ) : real;
begin
	argument := arctan ( y/x ) * 180/ pi;
end;
function TComplex. ComplexToStr ( ) : String;
begin
	if y>=0 then
		ComplexToStr := FloatToStrF ( x, ffFixed,5,2)+ ’+ ’ +
FloatTostrF ( y, ffFixed,5,2)+ ’ i ’
	else
		ComplexToStr := FloatTostrF ( x, ffFixed,5,2)+
FloatTostrF ( y, ffFixed,5,2)+ ’ i ’
end;
procedure TForm1. Button1Click ( Sender : TObject );
var Str1 : String;
	x1, x2 : real;
begin
	x1:= StrToFloat ( Edit1. Text );
	x2:= StrToFloat ( Edit2. Text );
	chislo :=TComplex. Create ( x1, x2 );
	chislo. x:= StrToFloat ( Edit1. Text );
	chislo. y:= StrToFloat ( Edit2. Text );
	Str1 := ’ Kompleksnoe _ c h i s l o _ ’+c h i s l o. ComplexToStr ( );
	Memo1. Lines. Add( Str1 );
	Str1 := ’ Modul  chisla  ’+
	FloatToStrF ( chislo. Modul ( ), ffFixed, 5, 2 );
	Memo1. Lines. Add( Str1 );
	Str1 := ’ Argument  chisla   ’+
	FloatToStrF ( chislo. Argument ( ), ffFixed, 5, 2 );
	Memo1. Lines. Add( Str1 );
	chislo. Free;
end;
initialization
	{$I unit1.lrs}
end.
< Лекция 8 || Лекция 9: 12345 || Лекция 10 >
Юрий Шутиков
Юрий Шутиков

По первому тесту выполнил дважды задания. Результат получается правильный (проверял калькулятором). Пишет, что "Задание не проверено" и предлагает повторить. 
 

Евгений Силуков
Евгений Силуков

Еще в декабре выполнил тест №1, а его все так и не проверили.