3

There is a virtual method in the baseclass that is overridden in the subclass.

However, I need to add a new parameter in the subclass method and it's impossible to use the "override" declaration, since the parameters are different.

Example:

type
  TFruit = class(TObject)
  public
    constructor Create; virtual;
  end;

  TApple = class(TFruit)
  public
    constructor Create(Color: TColor); override; // Error: Declaration of 'Create' differs from previous declaration
  end;

I know a good practice in this situation would be creating a new method with another name, but a lot of code would be redundant. This new parameter will affect just a few lines...

Then I thought of using "overload", but then I cannot use "override" together. So I ask: is there any problem in only using "overload"? (Delphi shows a Warning: Method 'Create' hides virtual method of base type 'TFruit')

I also checked the use of reintroduce + overload (to hide the warning above), but I also saw bad recommendations about this practice. What do you think?

And last, what if I just don't use none of them, just removing "override" in the subclass method and add the new param? (which gives me the same warning)

Anyone have any suggestion about what I should do in this case, to keep the good practices?

type
  TFruit = class(TObject)
  public
    constructor Create; virtual;
  end;

  TApple = class(TFruit)
  public
    constructor Create; override;

    // What should I do:
    //  constructor Create(Color: TColor); overload; // Shows a warning
    //  constructor Create(Color: TColor); reintroduce; overload; // Hides the warning
    //  constructor Create(Color: TColor); // Shows a warning
    //  Other solution?
  end;

Thanks!

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Roberto Schuster
  • 293
  • 2
  • 5
  • 16
  • 1
    You have a much bigger problem. The use of a virtual constructor implies that you wish to instantiate from a meta class. Which means that you must have only one constructor, the virtual one, potentially overridden in derived classes. – David Heffernan Mar 02 '15 at 21:25
  • 1
    Re (edit): Constructor or not, the existing answer already answers it. If you cannot override, a call to a CodToDesc on a TBaseClass variable pointing to a TSubClass instance will not run TSubClass.CodToDesc. That's all there is to it. – Sertac Akyuz Mar 03 '15 at 15:36
  • @Roberto Concerning your edit: Since the already given and highly upvoted answer deals with constructor, as your initial question asked, I advise to rollback the edit and ask a new question, therein possibly referring to this one. – NGLN Mar 03 '15 at 17:02
  • 1
    There's no need to ask a new question. The answer here covers it. The principle is much the same for normal methods and constructors. You make methods virtual so you can call on base class references and have polymorphic dispatch. You can't change the signature and still have polymorphic dispatch. You need to have a better understanding of polymorphism. That's your next move. – David Heffernan Mar 03 '15 at 17:15
  • https://stackoverflow.com/questions/34613100/delphi-reintroduce-and-overload-a-virtual-procedure – Gabriel Dec 03 '22 at 16:49

1 Answers1

14

Constructors in Delphi do not have to be named Create(). They can be named whatever you want. So if you need to introduce a new parameter, and it only affects a few lines of code, I would suggest creating a whole new constructor:

type
  TFruit = class(TObject)
  public
    constructor Create; virtual;
  end;

  TApple = class(TFruit)
  public
    constructor CreateWithColor(Color: TColor);
  end;

constructor TApple.CreateWithColor(Color: TColor);
begin
  inherited Create;
  // use Color as needed...
end;

The majority of your code would still be able to call TApple.Create(), and the few affected lines could call TApple.CreateWithColor() instead.

Otherwise, use reintroduce if you have to maintain the Create() name, and give it a default parameter so existing code will still compile:

type
  TFruit = class(TObject)
  public
    constructor Create; virtual;
  end;

  TApple = class(TFruit)
  public
    constructor Create(Color: TColor = clNone); reintroduce;
  end;

constructor TApple.Create(Color: TColor);
begin
  inherited Create;
  // use Color as needed...
end;

Just know that either way, if you are creating derived object instances using a class of TFruit metaclass (which is the usual reason for a virtual constructor), you won't be able to call either custom TApple constructor:

type
  TFruit = class(TObject)
  public
    constructor Create; virtual;
  end;
  TFruitClass = class of TFruit;

  TApple = class(TFruit)
  public
    constructor Create(Color: TColor = clNone); reintroduce;
    // constructor CreateWithColor(Color: TColor);
  end;

var
  Fruit: TFruit;
  Cls: TFruitClass;
begin
  Cls := TApple;
  Fruit := Cls.Create; // calls TFruit.Create() since it is not overridden in TApple...
  //...
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770