Difference between revisions of "Programming Using Objects Page 2"

From Lazarus wiki
Jump to navigationJump to search
Line 165: Line 165:
  
 
The fields f, f1 and f4 and methods m0, m1 and m4 all have public visibility; f1 and m1 by default (no specifier.)  Also, the order or repetition of visibility blocks is fairy flexible as can be seen from the above example.
 
The fields f, f1 and f4 and methods m0, m1 and m4 all have public visibility; f1 and m1 by default (no specifier.)  Also, the order or repetition of visibility blocks is fairy flexible as can be seen from the above example.
 +
 +
 +
== Objects - Run Time Library ==
 +
 +
FPC provides several predefined Object types for this  dialect.  By convention, all the supplied object types and sub types start with the letter "T".  These object types are included in the '''OBJECTS''' unit.  A similar looking set of types is suplied for the Classes object dialect which are declared in the '''SYSTEMS''' unit..  This can get confusing especially as both run time units declare a base object type (or class): ''TObject''.
 +
 +
For this Object dialect, ''TObject'' is the implicit root object which all objects descend from.  When no sub object is specified in an object type declaration, the type ''TObject'' is implicitly declared for you.
 +
 +
These predefined object types are documented in the FPC Run-Time Library Reference Guide, chapter 21. 
 +
 +
ftp://ftp.freepascal.org/pub/fpc/docs-pdf/rtl.pdf
 +
 +
This unit documents basic types and support routines as well as the following object types:

Revision as of 04:24, 9 March 2009

Objects - Self & Inherited

Self Keyword

Objects have an implicit parameter, self, which can be used in method calls which can be used to qualify fields and methods of the object. The explicit use of the keyword is optional but provides clarity if desired. The following implicit and explicit use of the self qualifier for field and method access within a method are identical. To illustrate this, let's say the the following (non useful) code was inserted into the Rectangle.Draw method:

<delphi> procedure Rectangle.Draw; begin

Self.x := 1; x := 1;

Self.Getparams; GetParams;

end; </delphi>

Inherited Keyword

A bit more useful is the keyword inherited for use within an object's methods. By using this keyword, one can explicitly call the parent method of the same name. This is useful because it allows a method overriding it's parent's methods the capability of using the parent's code before or after child object's code is called. The use of the inherited keyword can propagate up and inheritance chain. For our simple example program, there is input code common to all objects; the readln statements. Previously, this code had to be duplicated into the TSquare.GetParams method since it overrode the behavior of it's anscestor object types TRectangle and TShape. Now, using the inherited keyword, the GetParams method for TShape and TSquare can be implemented in the following manner to provide more efficient reuse of code.

<delphi>

procedure TShape.GetParams;

 begin

readln(x, y, width, height); writeln;

 end;
procedure TSquare.GetParams;
 begin

write('TSquare.GetParams : '); inherited; height := width; writeln('making sure all sides are equal for Square');

 end;

</delphi>

Note that there is no Draw method declared for TRectangle and the inherited method from TShape will be called implicitly. When the TSquare.Draw method is executed, it overrides the TShape.Draw method but after calling the writeln statement, it invoking the inherited TShape.Draw method. Then, after the inherited method returns, TSquare.Draw does some post processing. The inherited keyword is often useful in constructors for pre processing task like creating and initializing auxiliary objects and additional fields associated with the object. Similarly, the keyword is also useful in destructors for freeing up auxiliary objects and data structures the object previously created.. It should be noted that allthough code reuse and encapsulation is improved, program flow can be more difficult to follow than for straight procedural code.

Some languages allow the form inherited.methodname where method name is any method declared by an object. This implementation does not allow this construct.

Objects - Abstract Methods

Abstract methods are virtual methods which must be overridden in a child object. An abstract method is declared by adding the abstract keyword after the virtual keyword. There are no methods implemented for Objects with abstract methods declared which means no objects with abstract methods can be declared. Child objects must be created to provide overridden methods. The inherited keyword can not be used for child objects to call a parent abstract (non existent) method and depending on the situation, either the compiler will catch this and if it doesn't, a run time error will occur. An example declaration follows.

<delphi> Type

  TNewShape = Object
      f : longint;
     procedure GetParams; virtual;
     procedure Draw; virtual; abstract;
  end;

</delphi>

Although the example object drawing program might want to declare a shape type with abstract methods as shown above, a variable of TShape2 could not be declared which may or may not be a desired program feature.

Objects - Visibility Features

Static Fields

Normally, every instantiated object has its own privately maintained fields (i.e. separate individual memory locations) Child objects inherit the name of the field but the memory location is separate from all the other object fields of the same name qualified by the dot notation or scope. If the static keyword is added after the field name in the type definition, it signifies that this particular field is global for all instantiated object variables throughout the program which also propagates down the inheritance chain. The field then acts like a regular global variable with limited accessibility only via the object dot notation or in the local scope of object's methods. In addition, the type name itself can be used to access the global field. In order to use accidental use of the static field feature, the {$static on} compiler directive must be included in the source file. The following program illustrates the behavior of both regular and static fields.

<delphi> program StaticFieldsForever;

{$static on}

type

Ts1 =object f1 : longint; f2 : longint; static; end;

Ts2 =object (TS1) end;


var A1, B1 : Ts1; A2, B2 : Ts2;

begin writeln;

A1.f1:=2; B1.f1:=3; writeln('f1'); writeln(' A1 :', A1.f1, ' B1 :', B1.f1); writeln(' A2 :', A2.f1, ' B2 :', B2.f1); writeln('-------');

A2.f1:=4; writeln('f1'); writeln(' A1 :', A1.f1, ' B1 :', B1.f1); writeln(' A2 :', A2.f1, ' B2 :', B2.f1); writeln('-------');

B1.f2:=5; writeln('f1'); writeln(' A1 :', A1.f1, ' B1 :', B1.f1); writeln(' A2 :', A2.f1, ' B2 :', B2.f1); writeln('f2'); writeln(' A1 :', A1.f2, ' B1 :', B1.f2, ' T1 :', Ts1.f2); writeln(' A2 :', A2.f2, ' B2 :', B2.f2, ' T2 :', Ts2.f2); writeln('-------');

Ts2.f2:=6; writeln('f2'); writeln(' A1 :', A1.f2, ' B1 :', B2.f2, ' T1 :', Ts1.f2); writeln(' A2 :', A2.f2, ' B2 :', B2.f2, ' T2 :', Ts2.f2); writeln; end. </delphi> Resulting output

f1
 A1 :2  B1 :3
 A2 :0  B2 :0
-------
f1
 A1 :2  B1 :3
 A2 :4  B2 :0
-------
f1
 A1 :2  B1 :3
 A2 :4  B2 :0
f2
 A1 :5  B1 :5 T1 :5
 A2 :5  B2 :5 T2 :5
-------
f2
 A1 :6  B1 :6 T1 :6
 A2 :6  B2 :6 T2 :6

Public, Private, Protected

These specifiers are used for blocks of fields and methods declared in object types. The definitions of these specifiers are detailed in the language reference guide. Basically, public (or non specified) fields or methods are visible anywhere in the global scope of the program. Protected fields and methods are visible everywhere within the scope of a unit but limited only to objects and descendant objects outside of the unit they are declared in. Private fields and methods are only visible to objects and descended objects of the declared type. An example declaration follows:

<delphi> type

TMyObject =object f0: longint; procedure m0; public f1 : longint; procedure m1; protected f2 : longint; procedure m2; private f3 : longint; procedure m3; public f4 : longint; procedure m4; end; </delphi>

The fields f, f1 and f4 and methods m0, m1 and m4 all have public visibility; f1 and m1 by default (no specifier.) Also, the order or repetition of visibility blocks is fairy flexible as can be seen from the above example.


Objects - Run Time Library

FPC provides several predefined Object types for this dialect. By convention, all the supplied object types and sub types start with the letter "T". These object types are included in the OBJECTS unit. A similar looking set of types is suplied for the Classes object dialect which are declared in the SYSTEMS unit.. This can get confusing especially as both run time units declare a base object type (or class): TObject.

For this Object dialect, TObject is the implicit root object which all objects descend from. When no sub object is specified in an object type declaration, the type TObject is implicitly declared for you.

These predefined object types are documented in the FPC Run-Time Library Reference Guide, chapter 21.

ftp://ftp.freepascal.org/pub/fpc/docs-pdf/rtl.pdf

This unit documents basic types and support routines as well as the following object types: