Node:OOP, Next:Compiler Directives, Previous:Type Casts, Up:Programming
GNU Pascal follows the object model of Borland Pascal 7.0. The BP object extensions are almost fully implemented into GPC. This includes inheritance, virtual and non-virtual methods, constructors, destructors, pointer compatibility, extended `New' syntax (with constructor call and/or as a Boolean function), extended `Dispose' syntax (with destructor call).
The Borland object model is different from the ISO draft, but it will not be too difficult now to implement that too (plus the Borland Delphi Object Extensions which are quite similar to the ISO draft).
The syntax for an object type declaration is as follows:
program ObjectDemo; type Str100 = String (100); FooParentPtr = ^FooParent; FooPtr = ^Foo; FooParent = object constructor Init; destructor Done; virtual; procedure Bar (c: Real); virtual; function Baz (b, a, z: Char): Str100; { not virtual } end; Foo = object (FooParent) x, y: Integer; constructor Init (a, b: Integer); destructor Done; virtual; procedure Bar (c: Real); virtual; { overrides `FooParent.Bar' } z: Real; { GPC extension: data fields after methods } function Baz: Boolean; { new function } end; constructor FooParent.Init; begin WriteLn ('FooParent.Init') end; destructor FooParent.Done; begin WriteLn ('I''m also done.') end; procedure FooParent.Bar (c: Real); begin WriteLn ('FooParent.Bar (', c, ')') end; function FooParent.Baz (b, a, z: Char) = s: Str100; begin WriteStr (s, 'FooParent.Baz (', b, ', ', a, ', ', z, ')') end; constructor Foo.Init (a, b: Integer); begin inherited Init; x := a; y := b; z := 3.4; FooParent.Bar (1.7) end; destructor Foo.Done; begin WriteLn ('I''m done.'); inherited Done end; procedure Foo.Bar (c: Real); begin WriteLn ('Foo.Bar (', c, ')') end; function Foo.Baz: Boolean; begin Baz := True end; var Ptr: FooParentPtr; begin Ptr := New (FooPtr, Init (2, 3)); Ptr^.Bar (3); Dispose (Ptr, Done); New (Ptr, Init); with Ptr^ do WriteLn (Baz ('b', 'a', 'z')) end.
Remarks:
private
declarations and such.
These directives are syntactically accepted but ignored.
A pointer to FooParent
may be assigned the address of a
Foo
object. A FooParent
formal var
parameter
may get a Foo
object as the actual parameter. In such cases,
a call to a virtual
method calls the child's method, whereas
a call to a non-virtual
method selects the parent's one:
var MyFooParent: FooParentPtr; SomeFoo: Foo; [...] SomeFoo.Init (4, 2); MyFooParent := @SomeFoo; MyFooParent^.bar (3.14); { calls `foo.bar' } MyFooParent^.baz ('b', 'a', 'z'); { calls `fooParent.baz' } if SomeFoo.baz then { calls `foo.baz' } WriteLn ('Baz!');
In a method, an overwritten method of a parent object can be called
either prefixing it with the parent type name, or using the keyword
inherited
:
procedure Foo.Bar (c: Real); begin z := c; inherited bar (z) { or: FooParent.Bar (z) } end;
Use FooParent.bar (z)
if you want to be sure that this
method is called, even if somebody decides not to derive foo
directly from fooParent
but to have some intermediate object.
If you want to call the method bar
of the immediate parent -
whether it be fooParent
or whatever - use
inherited bar (z)
.
To allocate an object on the heap, use New
in one of the
following manners:
var MyFoo: FooPtr; [...] New (MyFoo, Init (4, 2)); MyFooParent := New (FooPtr, Init (4, 2))
The second possibility has the advantage that MyFoo
needn't
be a FooPtr
but can also be a FooParentPtr
, i.e. a
pointer to an ancestor of foo
.
Destructors can and should be called within Dispose:
Dispose (MyFooParent, Fini)