How do I overload a virtual function introduced in a parent class?
Asked Answered
N

2

9

I have a parent class with one important abstract procedure which I am overloading in many child classes as the example code shown below:

TCParent = Class
private
public
 procedure SaveConfig; virtual; abstract;

end;

TCChild = Class(TCParent)
private
public
 procedure SaveConfig; override;
end;

Now there I need to (overload) this procedure with another SaveConfig procedure that will accept parameters, yet I don't want to make big changes in the parent class that might require that I go and make changes in all other child classes.

Is there a way I can overload SaveConfig in this specific child class without making big changes to the parent class and other child classes that inherit from it?

Nickolenicks answered 5/12, 2012 at 1:16 Comment(2)
Why does this new 'SaveConfig' have to have the same name? Why not call it something else?Fronniah
@Fronniah Because when i want to add an overload to TStream.Seek that takes an Int64 offset. Don't confuse the question with the example.Olympia
C
14

You can use reintroduce to add a new overloaded method. Note that the order of reintroduce; overload; in the child class is required; if you reverse them, the code won't compile.

TCParent = Class
private
public
 procedure SaveConfig; virtual; abstract;
end;

TCChild = Class(TCParent)
private
public
 procedure SaveConfig; overload; override;
 procedure SaveConfig(const FileName: string); reintroduce; overload;
end;

(Tested in Delphi 7, so should work in it and all later versions.)

Complicated answered 5/12, 2012 at 1:39 Comment(7)
Unfortunately I am using Delphi 7 :( So when I tried to compile the above code I got the error: [Error] uClassChild.pas(13): Declaration of 'SaveConfig' differs from previous declaration Pointing to the line procedure SaveConfig(const FileName: string); reintroduce; override;Nickolenicks
You're out of luck, then. AFAIK, there's no way to do the same thing in D7 (which is why they introduced the new directive reintroduce <g>).Complicated
But reintroduce do exist in Delphi 7, it just doesn't compile with the above proc definition...to be more specific, D7 is not accepting reintroduce in this specific definition, but it will accept it normally in other definitionNickolenicks
I just started Windows XP Virtual Mode (so I had D7 available, copied and pasted the above code into a new VCL forms application (right after the form declaration), positioned the cursor inside the TCChild declaration, and hit Ctrl+Shift+C to complete the class declaration (and adding the method implementations). The code compiled fine, with no errors or warnings. Edited the question to reflect that change in version tested; I don't know why it doesn't compile for you, but it does here (Delphi 7.0 Build 4.453, according to Help->About).Complicated
reintroduce most likely dates back to D1, and possibly TP.Opportunist
Also, your first sentence is not accurate. You say "You can use reintroduce to add a new overridden method." But I guess you mean overloaded rather than overridden.Opportunist
@KenWhite I am not sure what was wrong but when I copied and pasted the code this time it worked! Anyway thanks a lot for your help :)Nickolenicks
A
5

Since you do not want to make changes to other descendants, I would suggest adding an optional field to the parent class to hold the parameters, then any descendant that wants to use parameters can use them. That way, you don't have to change the signature of the overridden SaveConfig(). For example:

type
  TCParent = class
  protected
    SaveConfigParams: TStrings; // or whatever...
  public
    procedure SaveConfig; overload; virtual; abstract;
    procedure SaveConfig(Params: TStrings); overload;
  end;

procedure TCParent.SaveConfig(Params: TStrings);
begin
  SaveConfigParams := Params;
  try
    SaveConfig;
  finally
    SaveConfigParams := nil;
  end;
end;

.

type
  TCChild = class(TCParent)
  public
    procedure SaveConfig; override;
  end;

procedure TCChild.SaveConfig;
begin
  if SaveConfigParams <> nil then
  begin
    // do something that uses the parameters...
  end else begin
    // do something else...
  end;
end;

.

type
  TCChild2 = class(TCParent)
  public
    procedure SaveConfig; override;
  end;

procedure TCChild2.SaveConfig;
begin
  // do something, ignoring the SaveConfigParams...
end;
Aglow answered 5/12, 2012 at 2:55 Comment(2)
Thanks for your help, but I am not sure I understood this part clearly....so just to make sure I understood you correctly...you mean that in child class depending on the SaveConfigParams in the IF statement I will execute code under the IF statement....if this is correct then what is the need of the parametrized SaveConfig procedure in the parent class?Nickolenicks
A child class can optionally check if parameters were specified if desired, and if detected then adjust its behavior accordingly, otherwise just ignore them and do something else. That is the whole point - the parameters are optional, but stored in the parent where each child can look if wanted. That is what you originally asked for - to support parameters without have to make changes everywhere. Ultimately, the better choice is to just bite the bullet and change SaveConfig() to give it optional input parameters, and then make that change in every child. Your code will be cleaner for it.Aglow

© 2022 - 2024 — McMap. All rights reserved.