• Шаблоны для вашего сайта
  • Сделать сайт
  • Реклама
  • Berry CSS
  • Albireo Framework
  • Бесплатный HTML-курс
  • Telegram-канал
  • Обратная связь
MaxSite.org
О создании сайтов и не только
Создание сайтов под ключ (Украина) →
Вход
×
или зарегистрироваться

Понимание ООП на примере Паскаля

PHP/ООППросмотров: 3137Комментарии: 05 июня 2020 г.

В продолжении предыдущей темы, что база программирования важнее самого языка, покажу на примере Turbo Pascal 7.0, что такое объекты в объектно-ориентированном программировании. (Чтобы было понятно, ООП в Паскале появился в 1989 году в версии TP 5.5.)

Если начинать изучать объекты, например с PHP, то не будет понимания, что это вообще такое. Зачем, например оператор new, что такое поля или методы? Такие вещи воспринимаются как часть языка, а всё что внутри — чёрный ящик, где происходят какие-то скрытые процессы. Вообще ООП — это парадигма, то есть описывает вроде как только общие принципы, а конкретная реализация зависит от языка. Но, на самом деле ООП в итоге всё равно превращается в обычный исполняемый код. На мой взгляд важно понимать откуда он берётся.

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

В ООП объект — это тип данных. Есть простые типы данных. Например тип Byte используется для хранения информации размером в один байт. Тип Word — занимает 2 байта и служит для хранения чисел от 0 до 65535.

Когда объявляется переменная, программа выделяет область памяти и именует её для идентификации. При этом компилятор обязательно проверит тип данных, которые пытаются в эту область записать. Если это тип Char (символьный), то в него никак не получится записать число.

В Паскале переменные объявляются в секции var (от «variables»):

var
   a: integer;
   s: string;

В данном случае типы integer и string — простые, о них знает компилятор Паскаля. Но, можно сделать и свои типы данных. Например объявим тип myInteger, который будет целочисленным LongInt.

type
   myInteger: LongInt;
 
var
   a: myInteger;

Секция type используется для декларирования составных типов. То есть вначале нужно описать тип данных, потом описать переменную этого типа, а уже после можно её использовать в самой программе. Из всех типов данных есть один особенный — процедурный — он указывает на функцию или процедуру.

Процедурный тип данных

Вначале я приведу полный код программы.

program sample_type_function;
{$F+}
 
{ TYPES }
type
    TMyFunc = function: string;
 
{ FUNCTIONS }
function f1: string;
begin
     f1 := 'this f1';
end;
 
function f2: string;
begin
     f2 := 'this f2';
end;
 
function f3(s: string): string;
begin
     f3 := 'this f3';
end;
 
{ VARIABLES }
var
    myFun: TMyFunc;
 
{ START PROGRAM }
begin
    writeln('=== MyFun ===');
 
    myFun := f1;
    writeln(myFun);
 
    myFun := f2;
    writeln(myFun);
 
    { ! ERROR: TYPE MISMATCH }
    { myFun := f3; }
 
    writeln('... press Enter ...');
    readln;
end.

Здесь объявляется процедурный тип TMyFunc.

В Паскале принято идентификаторы типов именовать с большой буквы «T».
Ключ {$F+} указывает компилятору использовать отложенное определение функций и процедур. За это отвечает опция компилятора «Force far calls».

Сама функция при этом вообще никак не определена. То есть глядя на это объявление, единственное, что мы можем увидеть — только то, что функция не имеет параметров и возвращает тип string.

Мы объявляем несколько функций: f1, f2, которые точно также не имеют параметров и возвращают строку. То есть по сути они полностью соответствуют по параметрам типу TMyFunc.

А вот функция f3, уже имеет входящий параметр, что делает её несовместимой с TMyFunc.

Имя функции, её параметры и тип возвращаемого результата определяют т.н. сигнатуру функции. В последующих версиях Паскаля (и других ЯП), сигнатура используется для перегрузки (перекрытия), то есть когда можно определить функцию с одним именем, но разными параметрами. Компилятор проверит входящие параметры и вызовет нужную функцию. Перекрытие функций есть не во всех языках, например его нет в PHP.

Теперь, чтобы использовать тип TMyFunc, нужно объявить переменную — у нас это myFun. А дальше она используется как обычно, путем присваивания. В первом примере вывода она будет f1, а во втором f2.

А вот присвоить f3 не получится. Компилятор сразу ругнётся с ошибкой «TYPE MISMATCH» (несовместимость типов).

Функции (и процедуры) — это подпрограммы. Они располагаются отдельными блоками в памяти и имеют точку входа. То есть вызывая f1, программа обратится к ячейке памяти, где начнётся выполняться эта подпрограмма. После выполнения произойдёт возврат из подпрограммы в основную программу.

Когда мы присваиваем myFun := f1; на самом деле создаётся лишь ссылка на адрес подпрограммы. Компилятор понимает, что myFun — процедурный тип, а значит в этой переменной будет храниться только адрес подпрограммы. Если мы попытаемся вызвать myFun без предварительного присваивания, то программа вывалится с ошибкой, поскольку переменная изначально ничего не содержит и ни на что не ссылается.

Тип Record (запись)

Другой тип данных — запись, которая хранит поля. Опять же приведу полный код программы.

program sample_rec;
{$F+}
 
{ TYPES }
type
	TMyFunc = function: string;
 
    TMyRec = record
           a: integer;
           c: char;
           f: TMyFunc;
    end;
 
{ FUNCTIONS }
function f1: string;
begin
    f1 := 'this f1';
end;
 
{ VARIABLES }
var
    myRec: TMyRec;
 
{ START PROGRAM }
begin
    writeln('=== MyRec ===');
 
    myRec.a := 1;
    myRec.c := 'a';
    myRec.f := f1;
 
    writeln(myRec.a);
    writeln(myRec.c);
    writeln(myRec.f);
 
    writeln('... press Enter ...');
    readln;
end.

Здесь объявляется тип TMyRec, который состоит из полей a, с и f. Работать с таким типом данных нужно аналогично: объявляется переменная (myRec), а после используется в коде. Чтобы получить доступ к полям используется символ точки «.».

Когда объявляется переменная myRec, компилятор выделит для этой структуры свою область памяти, где и будет хранить данные. Здесь также нужна инициализация полей, поскольку в начальный момент в памяти пусто (или мусор от других программ).

Нетрудно заметить, что процедурный тип и запись уже сильно напоминают объекты. Вот если мы их объединим, то и получим тип Объект.

Тип Object

Исходный код:

program sample_obj;
{$F+}
 
{ TYPES }
type
    TMyObj = object
         a: integer;
         c: char;
         procedure p;
    end;
 
{ FUNCTIONS }
procedure TMyObj.p;
begin
     a := 1;
     c := 'a';
end;
 
{ VARIABLES }
var
    MyObj: ^TMyObj;
 
{ START PROGRAM }
begin
    writeln('=== MyObj ===');
 
    new(MyObj);
 
    MyObj^.p;
    writeln(MyObj^.a);
    writeln(MyObj^.c);
 
    MyObj^.a := 2;
    MyObj^.c := 'b';

    writeln(MyObj^.a);
    writeln(MyObj^.c);
 
    writeln('... press Enter ...');
    readln;
end.

Для объявления объектов используется ключевое слово object. Внутри описываются поля так же, как и в записи. А процедуры/функции объявляются в полном виде (параметры и тип результата) и уже называются методы. Для доступа к полям и методам используется аналогичная нотация в виде точки.

В методах, в отличие от обычных процедур, автоматически доступны поля объекта. В других языках для этого приходится использовать специальное ключевое слово «this», указывающее на текущий объект. Именно поэтому в TMyObj.p нет секции var: мы сразу обращаемся к полям объекта.

Для работы с объектом нужно также создать переменную. Но здесь уже следует использовать «шляпки» — символ «^»: в Паскале это означает указатель, который ссылается на тип данных. Если по простому, то это ссылка на область памяти. В данном случае переменная MyObj как бы ссылается на TMyObj. Это довольно типовое поведение для ЯП. Например в PHP когда вы присваиваете какой-то переменной существующий объект, то обе переменные будут ссылаться на один и тот же объект в памяти. В Паскале переменная также указывает именно на объект в памяти, только делается это явно.

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

Обращение к полям и функциям объекта происходит также через точку и указатель. Точно такое же поведение и в других языках программирования, только не везде требуется указывать «шляпку». Это говорит о том, что объект — это в первую очередь ссылка на структуру данных в памяти.

Соберём воедино

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

// TYPES
class TMyObj {
   var $a;
   var $c;
 
   function p() {
      $this->a = 2;
      $this->c = 'b';
   } 
}
 
// START PROGRAM
$myObj = new TMyObj();
 
$myObj->p();
 
echo $myObj->a;
echo $myObj->c;

Фактически это тот же самый код из Паскаля, только в PHP часть работы оказалась скрыта: это делает код проще и удобней. Но при этом из кода PHP мы никогда не узнаем, что на самом деле есть указатели и переменные, которые также ссылаются на выделенную память объекта. Причём это отличается от поведения обычных php-переменных. Но узнать об этом можно только в справке. :-)

В этом плане Паскаль даёт хорошее представление даже о таких сложных вещах, как ООП. После его изучения, тот же PHP выглядит достаточно просто: обычные подпрограммы и классы, которые в большинстве случаев нужны только для ограничения области видимости. На мой взгляд, после Паскаля, большинство вещей в программировании становятся простыми и понятными, что позволяет перейти к использованию любого другого современного языка.


Создание сайтов (Украина) →
Обработка форм в PHP. Как это делать правильно в 2020 году
Какой язык программирования учить новичку
twitter.com facebook.com
Другие записи сайта
Работы по «MF». Редактирование записи на странице записи
Работы по «MF». Редактирование записи на странице записи
Визуальное программирование на Java
Визуальное программирование на Java
Шаблоны текста с помощью Punto Switcher
Шаблоны текста с помощью Punto Switcher
Новый PHP-фреймворк Igniter-zen-i-rails
Новый PHP-фреймворк Igniter-zen-i-rails
База SQLite и основы SQL. Часть 7
База SQLite и основы SQL. Часть 7
Антивирусы
Антивирусы
Оставьте комментарий!

Комментарий будет опубликован после проверки. Вы соглашаетесь с правилами сайта.

(обязательно)

Навигация
  • Шаблоны для MaxSite CMS 22
  • jQuery и JavaScript 6
  • Java и Android 5
  • PHP/ООП 25
  • SQL 17
  • Albireo Framework 11
  • Berry CSS 7
  • CSS, HTML, LESS, SASS 23
  • PHP 37
  • Тайм-менеджмент 9
  • Софт 37
  • SEO 13
  • Git. GitHub 3
  • CodeIgniter 5
  • Landing Page 3
  • Alpine.js 14
  • Фильмы 2
  • Дневник 55

Здесь можно заказать создание сайта (только Украина), шаблона или лендинга. Также вы можете выбрать готовые шаблоны для MaxSite CMS по небольшой цене. Также можно купить отдельные модули, компоненты для вашего сайта.

MaxSite.org
Как создать свой сайт

Услуги по созданию сайтов, блогов, лендингов
Обратная связь • Реклама на сайте
Карта сайта
Мои проекты
  • Шаблоны для вашего сайта
  • Заказать создание сайта
  • MaxSite CMS
  • Berry CSS (CSS Utilities)
  • Albireo Framework
  • UniCSS (Universal Atomic CSS)
  • Landing Page Framework
  • Бесплатные НТML-курсы
Ссылки
  • Telegram-канал
  • Github
  • Twitter
  • Telegram-бот
  • RSS
© MaxSite.org, 2006-2022. Работает на MaxSite CMS | Время: 0.3136 | SQL: 20 | Память: 4.63MB | Вход