Next: 4.6 Visibility
Up: 4. Objects
Previous: 4.4 Methods
Subsections
Methods are called just as normal procedures are called, only they have a
object instance identifier prepended to them (see also chapter Statements).
To determine which method is called, it is necessary to know the type of
the method. We treat the different types in what follows.
Static methods are methods that have been declared without a abstract
or virtual keyword. When calling a static method, the declared (i.e.
compile time) method of the object is used.
For example, consider the following declarations:
Type
TParent = Object
...
procedure Doit;
...
end;
PParent = ^TParent;
TChild = Object(TParent)
...
procedure Doit;
...
end;
PChild = ^TChild;
As it is visible, both the parent and child objects have a method called
Doit. Consider now the following declarations and calls:
Var ParentA,ParentB : PParent;
Child : PChild;
ParentA := New(PParent,Init);
ParentB := New(PChild,Init);
Child := New(PChild,Init);
ParentA^.Doit;
ParentB^.Doit;
Child^.Doit;
Of the three invocations of Doit, only the last one will call
TChild.Doit, the other two calls will call TParent.Doit.
This is because for static methods, the compiler determines at compile
time which method should be called. Since ParentB is of type
TParent, the compiler decides that it must be called with
TParent.Doit, even though it will be created as a TChild.
There may be times when you want the method that is actually called to
depend on the actual type of the object at run-time. If so, the method
cannot be a static method, but must be a virtual method.
To remedy the situation in the previous section, virtual methods are
created. This is simply done by appending the method declaration with the
virtual modifier.
Going back to the previous example, consider the following alternative
declaration:
Type
TParent = Object
...
procedure Doit;virtual;
...
end;
PParent = ^TParent;
TChild = Object(TParent)
...
procedure Doit;virtual;
...
end;
PChild = ^TChild;
As it is visible, both the parent and child objects have a method called
Draw. Consider now the following declarations and calls :
Var ParentA,ParentB : PParent;
Child : PChild;
ParentA := New(PParent,Init);
ParentB := New(PChild,Init);
Child := New(PChild,Init);
ParentA^.Doit;
ParentB^.Doit;
Child^.Doit;
Now, different methods will be called, depending on the actual run-time type
of the object. For ParentA, nothing changes, since it is created as
a TParent instance. For Child, the situation also doesn't
change: it is again created as an instance of TChild.
For ParentB however, the situation does change: Even though it was
declared as a TParent, it is created as an instance of TChild.
Now, when the program runs, before calling Doit, the program
checks what the actual type of ParentB is, and only then decides which
method must be called. Seeing that ParentB is of type TChild,
TChild.Doit will be called.
The code for this run-time checking of the actual type of an object is
inserted by the compiler at compile time.
The TChild.Doit is said to override the TParent.Doit.
It is possible to acces the TParent.Doit from within the
varTChild.Doit, with the inherited keyword:
Procedure TChild.Doit;
begin
inherited Doit;
...
end;
In the above example, when TChild.Doit is called, the first thing it
does is call TParent.Doit. You cannot use the inherited keyword on
static methods, only on virtual methods.
An abstract method is a special kind of virtual method. A method can not be
abstract if it is not virtual (this is not obvious from the syntax diagram).
You cannot create an instance of an object that has an abstract method.
The reason is obvious: there is no method where the compiler could jump to !
A method that is declared abstract does not have an implementation for
this method. It is up to inherited objects to override and implement this
method. Continuing our example, take a look at this:
Type
TParent = Object
...
procedure Doit;virtual;abstract;
...
end;
PParent=^TParent;
TChild = Object(TParent)
...
procedure Doit;virtual;
...
end;
PChild = ^TChild;
As it is visible, both the parent and child objects have a method called
Draw. Consider now the following declarations and calls :
Var ParentA,ParentB : PParent;
Child : PChild;
ParentA := New(PParent,Init);
ParentB := New(PChild,Init);
Child := New(PChild,Init);
ParentA^.Doit;
ParentB^.Doit;
Child^.Doit;
First of all, Line 4 will generate a compiler error, stating that you cannot
generate instances of objects with abstract methods: The compiler has
detected that PParent points to an object which has an abstract
method. Commenting line 4 would allow compilation of the program.
Remark that if you override an abstract method, you cannot call the parent
method with inherited, since there is no parent method; The compiler
will detect this, and complain about it, like this:
testo.pp(32,3) Error: Abstract methods can't be called directly
If, through some mechanism, an abstract method is called at run-time,
then a run-time error will occur. (run-time error 211, to be precise)
root
1999-06-10