Document Object Model
- 1 year ago
- 0
- 0
Object Pascal (с англ. — «Объектный Паскаль») — язык программирования , разработанный в фирме Apple Computer в 1986 году группой Ларри Теслера , который консультировался с Никлаусом Виртом . Произошёл от более ранней объектно-ориентированной версии Паскаль , называвшейся , который был доступен на компьютере Apple Lisa .
Изменения коснулись групп целых, символьных и строковых типов, которые стали разделяться на две категории:
Введена перегрузка процедур и функций, не являющихся членами объекта или класса. Перегружаются (с помощью ключевого слова overload ) отличающиеся типами и числом параметров процедуры и функции:
procedure Calc(I: Integer); overload;
// ...
procedure Calc(S: String; J: Integer); overload;
Введён для устранения рутинных операций выделения и возвращения памяти в heap-область (кучу), и для того, чтобы избежать случайных ошибок и утечки памяти. Элементы массива должны быть одинаковыми по типу. Нумерация элементов начинается с нуля.
Пример объявления:
var MyFlexibleArray: array of Real;
Использование:
var
A, B: array of Integer;
begin
SetLength(A, 1); //Выделяем память под один элемент
A[0] := 1; B := A;
B[0] := 2;
end;
Начиная с Delphi XE7 стали возможны следующие действия с динамическими массивами:
var M: array of integer;
begin
M := [1, 2, 3, 4, 5];
end;
M := M + [5, 6, 7];
Insert([6, 7, 8], M, 5); // вставка массива [6, 7, 8], в M, начиная с индекса 5
Delete(M, 1, 3); // удаляем 3 элемента, начиная с индекса 1
Concat([1, 2, 3, 4], [5, 6, 7])
То есть с динамическими массивами можно работать так же, как со строками.
В динамическом массиве также возможно задание открытого массива параметров, но тип их должен быть объявлен ранее, например:
type TDynamicCharArray = array of Char;
function Find(A: TDynamicCharArray): Integer;
В языке Object Pascal фирмы Borland появилась динамическая типизация , а также оператор динамического приведения типов as и оператор is для динамической проверки типов. Также в открытом массиве параметров стала возможна передача параметров различного типа (variant open array parameters).
В языке Object Pascal был введён вариантный тип данных ( Variant ), тип которых не известен на этапе компиляции и может изменяться на этапе выполнения программы. Однако этот тип данных поглощает больше памяти по сравнению с соответствующими переменными и операции над данными типа Variant выполняются медленнее. Более того, недопустимые операции над данными этого типа чаще приводят к ошибкам на этапе выполнения программы, в то время как подобные ошибки над данными другого типа были бы выявлены ещё на этапе компиляции.
Вариантные переменные могут принимать различные значения (целые, строковые, булевские, Currency , OLE-строки), быть массивами элементов этих же типов и массивом значений вариантного типа, а также содержать COM и CORBA объекты, чьи методы и свойства могут быть доступны посредством этого типа. Однако Variant не может содержать:
Variant можно смешивать (в выражениях и операторах) с другими вариантами, числовыми, строковыми и булевскими данными. При этом компилятор автоматически выполняет преобразование типа. Варианты, содержащие строки, не могут, однако, индексироваться (V[i] не допустимо).
var
V1, V2, V3, V4, V5: Variant;
I: Integer;
D: Double;
S: String;
begin
V1 := 1; //значение типа integer
V2 := 359.768; //значение типа real
V3 := 'Hello world!'; //значение типа string
end;
Стала возможна передача параметров различного типа. В оригинале он назван как «variant open array parameters». Тип данных определяется динамически в процессе выполнения программы. Так же как и в обычном открытом массиве функция High вызывается для определения числа элементов массива. Для объявления используются ключевые слова array of const . Пример:
function Output(const Args: array of const): string;
var
I: Integer;
begin
Result := '';
for I := 0 to High(Args) do with Args[I] do
case VType of
vtString: Result := Result + VString^;
vtPChar: Result := Result + VPChar;
vtInteger: Result := Result + IntToStr(VInteger);
vtBoolean: Result := Result + BoolToStr(VBoolean);
vtChar: Result := Result + VChar;
vtExtended: Result := Result + FloatToStr(VExtended^);
vtObject: Result := Result + VObject.ClassName;
vtClass: Result := Result + VClass.ClassName;
vtVariant: Result := Result + string(VVariant^);
vtInt64: Result := Result + IntToStr(VInt64^);
vtAnsiString: Result := Result + string(VAnsiString);
vtCurrency: Result := Result + CurrToStr(VCurrency^);
end;
Result := Result + ' ';
end;
//...
Output(['test', 777, '@', True, 3.14159, TForm]); //передача открытого массива параметров
Будет возвращена строка: «test 777 @ T 3.14159 TForm».
Как видно, имеет свою внутреннюю структуру, обращение к которой даёт возможность определить тип данных. В строке вызова функции создаётся массив, с помощью конструктора открытого массива , который использует квадратные скобки.
Для введения новой объектной модели введено ключевое слово class (в Turbo Pascal ключевое слово object ).
Введены операторы для проверки и приведения классов is и as динамически в ходе выполнения программы. Появились указатели на методы, для чего введено новое использование ключевого слова object :
type
TMyMethod = procedure (Sender : Object) of object;
В Turbo Pascal можно было работать как с динамическими, так и со статическими экземплярами объектов.
В объектной модели Object Pascal программист работает только с динамическими экземплярами классов, выделяемых в heap-области (куче). В связи с этим изменён синтаксис обращения к полям и методам объектов.
Ранее для работы с динамическими экземплярами объектов, инициализированными с использованием обращения к конструктору в сочетании с функцией New , необходимо было использовать обращение по указателю (^). Теперь тип класса стал являться по умолчанию также указателем.
Пример для сравнения:
Объектная модель в Turbo Pascal :
type
PMyObject = ^TMyObject;
TMyObject = object (TObject)
MyField : PMyType;
constructor Init;
end;
//...
var
MyObject : PMyObject;
begin
MyObject := New(PMyObject,Init);
MyObject^.MyField := //...
end;
Новая объектная модель в Object Pascal :
type
TMyObject = class (TObject)
MyField : TMyType;
constructor Create;
end;
//...
var
MyObject : TMyObject;
begin
MyObject := TMyObject.Create;
MyObject.MyField := //...
end;
Было изменено соглашение об именовании конструкторов и деструкторов. В старой объектной модели вызов New отвечал за распределение памяти, а обращение к конструктору инициализировало выделенную область памяти. В новой модели эти действия выполняет конструктор Create . Начиная с версии Delphi XE появились статические методы класса.
Появилась возможность ограничивать видимость членов класса (методы, свойства), которые предназначены для использования только в реализации производных классов. Это даёт возможность защищать исходный код от модификации пользователями класса. Такие методы содержатся в секции protected (защищённые) в объявлении класса.
Появились понятия свойства ( property ) и связанные со свойствами ключевые слова read , write , stored , default ( nodefault ), index . Свойства визуальных объектов, видимых в интегрированной среде разработки , объявляются с помощью нового слова published в качестве секции в объявлении класса, являющегося визуальным объектом.
type
{объявление}
generic TList<T> = class
Items: array of T;
procedure Add(Value: T);
end;
implementation
{реализация}
procedure TList.Add(Value: T);
begin
SetLength(Items, Length(Items) + 1);
Items[Length(Items) - 1] := Value;
end;
Общий класс может быть просто специализирован для конкретного типа с использованием ключевого слова specialize :
type
TIntegerList = specialize TList<Integer>;
TPointerList = specialize TList<Pointer>;
TStringList = specialize TList<string>;
Разработчики TMT Pascal (модификация Object Pascal) первыми ввели полноценную перегрузку операторов , что впоследствии было перенято разработчиками других диалектов языка: Delphi (с Delphi 2005), Free Pascal и др.
Пример:
{объявление}
type
TVector = packed record
A, B, C: Double;
procedure From(const A, B, C: Double);
class operator Add(const Left, Right: TVector): TVector;
class operator Implicit(const v: TVector): TPoint;
end;
{реализация}
implementation
//...
class operator TVector.Add(const Left, Right: TVector): TVector;
begin
Result.A := Left.A + Right.A;
Result.B := Left.B + Right.B;
Result.C := Left.C + Right.C;
end;
class operator TVector.Implicit(const v: TVector): TPoint;
begin
Result.A := round(v.A);
Result.B := round(v.B);
end;
//...
{использование}
var
v1, v2: TVector;
begin
v1.From(20, 70, 0);
v2.From(15, 40, 4);
Canvas.Polygon([v1, v2, v1 + v2]);
end;
Начиная с версии среды Delphi 7, фирма Borland стала официально называть язык Object Pascal как Delphi .
Язык Object Pascal поддерживается и развивается другими разработчиками. Наиболее серьёзные реализации Object Pascal (помимо Delphi) — это кроссплатформенный (версия языка Turbo Pascal ) мультиязыковой среды TopSpeed , TMT Pascal , Virtual Pascal , PascalABC.NET , Free Pascal , GNU Pascal . Язык программирования Oxygene является диалектом Object Pascal для платформы .NET и дальнейшим его развитием, а новыми возможностями языка является оператор ":", асинхронный и отложенный вызовы методов, асинхронное выполнение блока кода, параллельные циклы, анонимные конструкторы, элементы контрактного и аспектно-ориентированного программирования и др. (компилятор распространяется без ограничений).
program ObjectPascalExample;
type
THelloWorld = object
procedure Put;
end;
var
HelloWorld: THelloWorld;
procedure THelloWorld.Put;
begin
WriteLn('Hello, World!');
end;
begin
New(HelloWorld);
HelloWorld.Put;
Dispose(HelloWorld);
end.
Delphi (для обеспечения обратной совместимости) и Free Pascal также поддерживают этот вариант синтаксиса.
program ObjectPascalExample;
type
PHelloWorld = ^THelloWorld;
THelloWorld = object
procedure Put;
end;
var
HelloWorld: PHelloWorld; { это указатель на THelloWorld }
procedure THelloWorld.Put;
begin
WriteLn('Hello, World!');
end;
begin
New(HelloWorld);
HelloWorld^.Put;
Dispose(HelloWorld);
end.
В Free Pascal этот вариант синтаксиса доступен в режимах ObjFpc и Delphi .
program ObjectPascalExample;
type
THelloWorld = class { определение класса }
procedure Put;
end;
procedure THelloWorld.Put; { описание процедуры метода Put класса THelloWorld }
begin
Writeln('Hello, World!');
end;
var
HelloWorld: THelloWorld; { определение переменной-указателя на экземпляр класса }
begin
HelloWorld := THelloWorld.Create; { конструктор возвращает значение указателя на экземпляр класса }
HelloWorld.Put;
HelloWorld.Free; { деструктор уничтожает экземпляр класса и освобождает область памяти }
end.