New OOP concepts in Object Pascal

Lecture




  New OOP concepts in Object Pascal

In the Object Pascal language used in Delphi, there have been a number of changes that were long awaited by programmers, compared to the latest version of Borland Pascal. Here are the main ones that allowed us to call the Object Pascal object model a new object model:

  • changes in the syntax of the declaration and use of objects
  • introduction of class functions
  • introduction of class methods
  • changes in the organization of definitions and method calls
  • introduction of the declaration section of the object type developer interface - protected
  • introduction of the object type interface design-time declaration section - published
  • Introduction of RTTI mechanisms - information about types at the program execution stage
  • introduction of procedural support
  • introduction of the concept of "property" - property
Unlike the old object type declarations that used the object keyword , new object types are defined using the class word . Here it is appropriate to give the definition of the relationship between the concepts of an object and a class given by Gradi Buch:



In the new object model, the programmer works only with dynamic instances of classes (that is, with those for which memory is allocated in the heap-area), unlike the old model, where it was possible to work with both dynamic and static instances. For this reason, the syntax for accessing fields and methods of objects has been changed. If earlier, to work with dynamic instances of objects (initialized using a call to the constructor in combination with the New function ), the programmer had to use the "by address" ( ^ ) call , now such access is automatically implied. As an example, compare the following two source code snippets:

{Old object model}

type

PMyObject = ^ TMyObject;

TMyObject = object (TObject)

MyField: PMyType;

constructor Init;

end;

...

var

MyObject: PMyObject;

begin

MyObject: = New (PMyObject, Init);

MyObject ^ .MyField: = ...

end;

{New Object Model}

type

TMyObject = class (TObject)

MyField: TMyType;

constructor Create;

end;

...

var

MyObject: TMyObject;

begin

MyObject: = TMyObject.Create;

MyObject.MyField: = ...

end;

As you can see, Object Pascal has extended the syntax for using “dot notation” to access object methods. In addition, the agreement on the naming of constructors and destructors has been changed. In the old object model, the call to New was responsible for allocating memory, and the call to the constructor initialized the allocated area of ​​memory. In the new model, these functions are performed by the Create constructor .

Here is the declaration of the base for all object types of the TObject class:

TObject = class

constructor Create;

destructor Destroy; virtual;

procedure Free;

class function NewInstance: TObject; virtual;

procedure FreeInstance; virtual;

class procedure InitInstance (Instance: Pointer): TObject;

function ClassType: TClass;

class function ClassName: string;

class function ClassParent: TClass;

class function ClassInfo: Pointer;

class function InstanceSize: Word;

class function InheritsFrom (AClass: TClass): Boolean;

procedure DefaultHandler (var Message); virtual;

procedure Dispatch (var Message);

class function MethodAddress (const Name: string):

Pointer;

class function MethodName (Address: Pointer): string;

function FieldAddress (const Name: string): Pointer;

end;

Object Pascal compiler is the basis of Delphi. Visual Delphi tools are built on the concept of Two-Way Tools , which allows you to synchronize the process of visual design of application forms with the generation of source code.

Such an architecture is possible only if there is a type information support mechanism - RTTI (RunTime Type Information) . The basis of such a mechanism is the internal structure of classes and, in particular, the ability to access it through the use of class methods described by the class function construction ... Let us define the concept of a class method:



On the one hand, Delphi, being a visual development environment for applications, is aimed at those programmers who, from ready-made components, “build” specific applications for end users. On the other hand, being an expandable object-oriented tool, this product is also of interest to professionals involved in enhancing the functionality of existing software libraries. Therefore, the appearance in Object Pascal of new sections in the description of classes, respectively, published and protected , looks absolutely logical . Together with the previously introduced sections ( public and private ), they provide full control over the possibilities of using and "painless" (in the sense of preventing fatal from the ideological point of ideology of errors) modification of the components of the Visual Component Library (VCL - Delphi class library). To clarify the logic of using new sections, we also give a brief description of existing ones:

  • private - internal implementation details
  • protected - developer's interface
  • public - run-time interface
  • published - design-time interface
All these sections work at the module level (in the sense of the Pascal language): if any part of the object is available (or not available) in one area of ​​the module, then the same accessibility will be determined in another area of ​​the module (for classes declared in section In te rface). If you need special protection of an object or its part, then for this it is necessary to place it in a separate module.

The protected section combines the functional load of the private and public sections in such a way that if you want to hide the internal mechanisms of your object from the end user, this user will not be able to use any of the object declarations from his protected area at run-time , but this will not prevent the developer New components use these mechanisms in other modules. That is, protected- declarations are available from any of the heirs of your class.

The published section turned out to be necessary when introducing the ability to set the properties and behavior of components in Delphi even at the stage of form design and the application itself. It is the published ads that are available through the Object Inspector, be it property references or event handlers.

It should be noted that, when spawning a new class, it is possible to transfer ads from one section to another, with the only limitation - if you hide the ad due to its transfer to the private section - later on it will be pulled out by the successor to a more accessible section. in another module will be no longer possible. This limitation, fortunately, does not apply to dynamic message handling methods in Windows.

Considering that inheritance is one of the cornerstones of object ideology, the obvious problem of implementing object-oriented language is the problem of dispatching calls to methods of objects.



Object Pascal methods can be of any of three types: static, virtual, or dynamic .

Since static and virtual methods have not undergone fundamental changes, in comparison with Borland Pascal 7.0, we will dwell on a new type of implementation - dynamic (which, generally speaking, was present in an implicit form in the OWL library).

Dynamic ( dynamic ) methods, according to the possibilities of inheritance and overlap, are similar to virtual, but unlike the latter, they do not have entries in the VMT table . This approach allows to reduce the memory consumption with a large number of these methods and the classes themselves.





Unlike virtual methods and the VMT ideology itself, the dynamic method table (DMT) contains entries only for methods declared or overlapped for a given class. Each dynamic method has only one reference, represented by the so-called "index", which is used to search for the method to call (basic information on the processing of dynamic methods is contained in the module x: \ delphi \ source \ rtl \ sys \ dmth.asm ). From a syntax point of view, dynamic and virtual methods overlap in the same way — using the override keyword . The exception is handlers for Windows messages wm_Xxx .

In Delphi, there are concepts that are fundamentally new to the already existing object-oriented implementations of Pascal. These concepts include properties, a class function, and an object reference .

Object Pascal adds the ability to define fields of a procedural type. Obviously, in the body of the functions associated with these fields, the developer needs access to other fields of the object, methods, etc. The possibility of such access is based on the transfer to these functions of an implicit, but available in their code, parameter that automatically takes the value of the field of the Self object . Such functions are called class functions . To declare functions of classes, you must use the special function function ... of object .

Delphi allows you to create a special object type handle (of type, not of instance!), Known as object reference - object reference.

Object references are used in the following cases:

  • type of object being created is not known at compile time
  • you need to call a class method whose type is not known at compile time
  • as the right operand in validation and type conversion operations using is and as (we will talk about them when discussing RTTI mechanisms in Chapter 1.4)
An object reference is defined using the class of ... construct . Here is an example of declaring and using class reference:

type

TMyObject = class (TObject)

MyField: TMyObject;

constructor Create;

end;

TObjectRef = class of TObject;

...

var

ObjectRef: TObjectRef;

s: string;

begin

ObjectRef: = TMyObject; {assign a type, not an instance!}

s: = ObjectRef.ClassName; {string s contains 'TMyObject'}

end;

Thus, in Delphi, a special reference TClass is defined , compatible with assignment with any successor of TObject. Similarly, TPersistentClass and TComponentClass are declared .

The methods in the new object model use the same calling conventions as regular procedures or functions, with some exceptions. The "key" of the internal organization of calls to object methods is the fact that for each method, in addition to the declared parameters, an implicit Self parameter is passed , which is described for each class or object instance. The Self parameter is always passed last and is a pointer . For ordinary methods, Self is a pointer to an object instance, for class methods it is a pointer to a Virtual Method Table (VMT). For example, for this ad:

type

TMyObject = class (TObject)

procedure One;

procedure Two; virtual;

class procedure Three; virtual;

end;

TMyClass = class of TObject;

...

var

MyObject: TMyObject;

MyClass: TMyClass;

calling MyObject.One will generate the following code:

les DI, MyObject

push ES

push DI

call MyObject.One

When returning control, the method must first remove the Self parameter from the stack , and then the rest, the explicit parameters.

Methods always use the far ( call) model, regardless of how the compiler directive $ F is set . To call a virtual method, the compiler generates a code that loads a pointer to VMT from the object , and then calls the method associated with this entry point via the VMT entry point (ES: [DI] ). For example, calling MyObject.Two will generate the following :

les DI, MyObject

push ES

push DI

les DI, ES: [DI]

call DWORD PTR ES: [DI]

Call MyObject.Three :

les DI, MyObject

les DI, ES: [DI]

push ES

push DI

call DWORD PTR ES: [DI + 4]

; 4, because this offset in vmt for the second

; on the virtual method account

And for MyClass.Three will be generated:

les DI, MyClass

push ES

push DI

call DWORD PTR ES: [DI + 4]

Obviously, the examples of generated code correspond to the 16-bit version of Delphi, but by their ideology they remain true for Delphi32.


Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Programming Languages and Methods / Translation Theory

Terms: Programming Languages and Methods / Translation Theory