Next: 6. Expressions
Up: 5. Classes
Previous: 5.3 Methods
Classes can contain properties as part of their fields list. A property
acts like a normal field, i.e. you can get or set it's value, but
allows to redirect the access of the field through functions and
procedures. They provide a means to assiciate an action with an assignment
of or a reading from a class 'field'. This allows for e.g. checking that a
value is valid when assigning, or, when reading, it allows to construct the
value on the fly. Moreover, properties can be read-only or write only.
The prototype declaration of a property is as follows:
Properties
A read specifier is either the name of a field that contains the
property, or the name of a method function that has the same return type as
the property type. In the case of a simple type, this
function must not accept an argument. A read specifier is optional, making
the property write-only.
A write specifier is optional: If there is no write specifier, the
property is read-only. A write specifier is either the name of a field, or
the name of a method procedure that accepts as a sole argument a variable of
the same type as the property.
The section (private, published in which the specified function or
procedure resides is irrelevant. Usually, however, this will be a protected
or private method.
Example:
Given the following declaration:
Type
MyClass = Class
Private
Field1 : Longint;
Field2 : Longint;
Field3 : Longint;
Procedure Sety (value : Longint);
Function Gety : Longint;
Function Getz : Longint;
Public
Property X : Longint Read Field1 write Field2;
Property Y : Longint Read GetY Write Sety;
Property Z : Longint Read GetZ;
end;
Var MyClass : TMyClass;
The following are valid statements:
WriteLn ('X : ',MyClass.X);
WriteLn ('Y : ',MyClass.Y);
WriteLn ('Z : ',MyClass.Z);
MyClass.X := 0;
MyClass.Y := 0;
But the following would generate an error:
MyClass.Z := 0;
because Z is a read-only property.
What happens in the above statements is that when a value needs to be read,
the compiler inserts a call to the various getNNN methods of the
object, and the result of this call is used. When an assignment is made,
the compiler passes the value that must be assigned as a paramater to
the various setNNN methods.
Because of this mechanism, properties cannot be passed as var arguments to a
function or procedure, since there is no known address of the property (at
least, not always).
If the property definition contains an index, then the read and write
specifiers must be a function and a procedure. Moreover, these functions
require an additional parameter : An integer parameter. This allows to read
or write several properties with the same function. For this, the properties
must have the same type.
The following is an example of a property with an index:
uses objpas;
Type TPoint = Class(TObject)
Private
FX,FY : Longint;
Function GetCoord (Index : Integer): Longint;
Procedure SetCoord (Index : Integer; Value : longint);
Public
Property X : Longint index 1 read GetCoord Write SetCoord;
Property Y : Longint index 2 read GetCoord Write SetCoord;
Property Coords[Index : Integer] Read GetCoord;
end;
Procedure TPoint.SetCoord (Index : Integer; Value : Longint);
begin
Case Index of
1 : FX := Value;
2 : FY := Value;
end;
end;
Function TPoint.GetCoord (INdex : Integer) : Longint;
begin
Case Index of
1 : Result := FX;
2 : Result := FY;
end;
end;
Var P : TPoint;
begin
P := TPoint.create;
P.X := 2;
P.Y := 3;
With P do
WriteLn ('X=',X,' Y=',Y);
end.
When the compiler encounters an assignment to X, then SetCoord
is called with as first parameter the index (1 in the above case) and with
as a second parameter the value to be set.
Conversely, when reading the value of X, the compiler calls
GetCoord and passes it index 1.
Indexes can only be integer values.
You can also have array properties. These are properties that accept an
index, just as an array does. Only now the index doesn't have to be an
ordinal type, but can be any type.
A read specifier for an array property is the name method function
that has the same return type as the property type.
The function must accept as a sole arguent a variable of the same type as
the index type. For an array property, you cannot specify fields as read
specifiers.
A write specifier for an array property is the name of a method
procedure that accepts two arguments: The first argument has the same
type as the index, and the second argument is a parameter of the same
type as the property type.
As an example, see the following declaration:
Type TIntList = Class
Private
Function GetInt (I : Longint) : longint;
Function GetAsString (A : String) : String;
Procedure SetInt (I : Longint; Value : Longint;);
Procedure SetAsString (A : String; Value : String);
Public
Property Items [i : Longint] : Longint Read GetInt
Write SetInt;
Property StrItems [S : String] : String Read GetAsString
Write SetAsstring;
end;
Var AIntList : TIntList;
Then the following statements would be valid:
AIntList.Items[26] := 1;
AIntList.StrItems['twenty-five'] := 'zero';
WriteLn ('Item 26 : ',AIntList.Items[26]);
WriteLn ('Item 25 : ',AIntList.StrItems['twenty-five']);
While the following statements would generate errors:
AIntList.Items['twenty-five'] := 1;
AIntList.StrItems[26] := 'zero';
Because the index types are wrong.
Array properties can be declared as default properties. This means that
it is not necessary to specify the property name when assigning or reading
it. If, in the previous example, the definition of the items property would
have been
Property Items[i : Longint]: Longint Read GetInt
Write SetInt; Default;
Then the assignment
AIntList.Items[26] := 1;
Would be equivalent to the following abbreviation.
AIntList[26] := 1;
You can have only one default property per class, and descendent classes
cannot redeclare the default property.
root
1999-06-10