I have the following classes declared in a single file:
type
TCongruence = class(TObject)
private
a, b, n, numClass: integer;
solutions, vals: TSolutions;
hasSolutions: boolean;
function divides(a, b: integer): boolean;
function modulo(a, b: integer): integer;
public
constructor Create(a, b, n: integer); virtual;
function getSolutions: TSolutions; virtual;
function gcdExtended(p, q: integer): TSolutions;
class function getGCD(u, v: integer): integer;
property valA: integer read a;
property valB: integer read b;
property valN: integer read n;
property getClass: integer read numClass;
property hasSol: boolean read hasSolutions;
end;
type
TConguenceSystem = class(TCongruence)
private
system: array of TCongruence;
public
constructor Create(a: array of TCongruence); override;
function getSolutions: integer; override;
end;
The second one as you can see is a subclass because I need to use all the functions implemented in the TCongruence
class. I have declared the constructor virtual so that I can call the override on the descendant.
Is that correct? Do I have to remove the virtual/override and simply use the constructor like this? (below)
constructor Create(a: array of TCongruence);
I guess that in this case I am hiding the father's constructor. I have declared this constructor:
constructor TConguenceSystem.Create(a: array of TCongruence);
var i: integer;
begin
SetLength(system, length(a)); // private var system: array of TCongruence
for i := Low(a) to High(a) do
begin
system[i] := a[i];
end;
solutions := false;
end;
When you intend to override behaviour of a method with the same signature in a descendent class then you must declare it virtual
in the base class and the descendent class would then use override
.
If, however, you wish to introduce a new method with a different signature then you must use the overload
directive if you are declaring the method within the same class. This simply allows re-use of the same method name for what are, effectively, entirely different methods with different signatures. For example :
TCongruence = class(TObject)
public
constructor Create(a : integer); overload;
constructor Create(a, b, n: integer); overload;
end;
If you are declaring a new method in a descendent class, however, with a different signature then none of these decorations are required.
TCongruence = class(TObject)
public
constructor Create(a, b, n: integer);
end;
TCongruenceSystem = class(TCongruence)
public
constructor Create(a: array of TCongruence);
end;
The above is fine - you are not overriding the original constructor, you are simply introducing a new one with a new signature. Since the latter belongs to a new class with a different name there is no ambiguity and overload
is not required. You can even access the ancestor methods in the usual way here :
TCongruence = class(TObject)
private
Fa, Fb, Fn : integer;
public
constructor Create(a, b, n: integer);
end;
TCongruenceSystem = class(TCongruence)
private
FArr : array of TCongruence;
public
constructor Create(a: array of TCongruence);
end;
constructor TCongruence.Create(a, b, n: integer);
begin
inherited Create;
Fa := a;
Fb := b;
Fn := n;
end;
constructor TCongruenceSystem.Create(a: array of TCongruence);
var
c : TCongruence;
i : integer;
begin
inherited Create(a[0].Fa, a[1].Fb, a[2].Fn);
SetLength(FArr, Length(a));
i := 0;
for c in a do begin
FArr[i] := c;
Inc(i);
end;
end;
Without the overload
directive, however, the following would not be allowed :
var
cs : TCongruenceSystem;
begin
cs := TCongruenceSystem.Create(1, 2, 3);
end.
since TCongruenceSystem
is hiding the base class Create
which takes three integer
arguments. If you allow the overload
, however :
TCongruence = class(TObject)
private
Fa, Fb, Fn : integer;
public
constructor Create(a, b, n: integer); overload;
end;
TCongruenceSystem = class(TCongruence)
private
FArr : array of TCongruence;
public
constructor Create(a: array of TCongruence); overload;
end;
Then the above call of cs := TCongruenceSystem.Create(1, 2, 3);
would be allowed and the ancestor constructor would be used to build the descendent class.
These approaches can be combined, for example :
TCongruence = class(TObject)
public
constructor Create(a : integer); overload; virtual; {overridable}
constructor Create(a, b, n: integer); overload; {only in base}
end;
TCongruenceSystem = class(TCongruence)
public
constructor Create(a:integer); overload; override; {overrides parent}
constructor Create(a: string); overload; {introduce new}
end;
In the case of the constructor you are introducing a method with a different set of parameters so this is allowed. In the case of getSolutions
, however, the function is takes no parameters and differs only in the return type. An overloaded method needs to have a different parameter set, however, so this type of mutation is not allowed in a descendent class. getSolutions
in the descendent class would need to take a different name if you intend it to also be a parameterless function with a different return type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With