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