3

I'm new into the Delphi coding and I get an error when trying to override a constructor , can you advice me on what I'm doing wrong or what should I do to get to the desired result.

I want to override the constructor of a frame so that it will chance the Caption of an label it containts to a specific text.

here is the code

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TfrmMesaj = class(TFrame)
    Panel1: TPanel;

  private
    { Private declarations }
  public
    { Public declarations }
    constructor Create(name : string);  override;
  end;

implementation

{$R *.dfm}

{ TfrmMesaj }



{ TfrmMesaj }

constructor TfrmMesaj.Create(name: string);
begin
  inherited;
   Panel1.Color := clRed;
   Panel1.Caption := name;
end;

end.

When I try to compile I get the following errors :

[DCC Error] frameMesaj.pas(17): E2037 Declaration of 'Create' differs from previous declaration
[DCC Error] frameMesaj.pas(32): E2008 Incompatible types

What Am I doing wrong and how can I achive what I want?

CiucaS
  • 2,010
  • 5
  • 36
  • 63

3 Answers3

9

Stefan has explained why your override isn't working. Basically, whenever you override a virtual method the signatures of the two methods must match exactly. However, I'm strongly opposed to the use of reintroduce. And I'll explain why at the bottom of this answer. (Please also note that reintroduce quite specifically does not override the ancestor method. It only hides the warning that the method is hiding the ancestor's method.)

A couple of better options:

Use a different name for your constructor

You don't have to name your constructors Create. You could for example add a second constructor as: constructor CreateWithCaption(AName: string);. Note that I didn't even make this constructor virtual. Only make methods virtual if you intend them to behave polymorphically. (Which means you want subclasses to be able to change the implementation even when called from the base class.)

This option is very much like overload as suggested by Stefan.

Use a factory method to create your frame

As systems get larger it can be useful to separate the processing of creating some objects from the work they actually do. This is done using factory methods whose sole purpose is to create other objects that are ready to interact with the rest of your system. E.g.

//I've chosen to demonsrate this on a form, but you could also implement a dedicated factory class
function TMyForm.CreateMessageFrame(ACaption: string): TFrame;
begin
  //Note the factory method intends the form to own all frames created.
  Result := TfrmMesaj.Create(Self);
  
  //The factory method ensures the frame is "ready"
  //This does violate Law of Demeter, but you could easily add a method to the fram to resolve that.
  Result.Panel1.Color := clRed;
  Result.Panel1.Caption := ACaption;
end;

What's wrong with reintroduce anway?

  • Reintroduce is only applicable when the method on the base class is virtual.
  • The method should only be virtual if it's intended to be used polymorphically.
  • This means that the method is intended to be called from a base class reference, but might need to take special action to work correctly in some subclasses.

Since your question was dealing with overriding TComponent.Create, it will serve very nicely to illustrate by way of example.

  • constructor TComponent.Create(AOwner: TComponent); is virtual quite specifically so component creation behaves polymorphically. This is so that when components are streamed from a .DFM file they will be created correctly even though the reference used to create them is of type TComponent.
  • If you hide this constructor, then any special actions you need to take when your frame is streamed and created from a .DFM will not happen.
  • Also any subclasses of your frame will not be able to override constructor Create(AOwner: TComponent); because it is hidden.
Community
  • 1
  • 1
Disillusioned
  • 14,635
  • 3
  • 43
  • 77
  • 1
    Note that there can be reasons to overload Create: if the class is to be used in C++Builder as well. In Delphi, you can have constructors `Create(Integer)` and `CreateOtherWay(Integer)`. In C++, this would cause a name clash and your class would be unusable in C++Builder. I am all for using different constructor names for different purposes, but don't forget that if C++Builder compatibility is required, you are not entirely free in your moves. – Rudy Velthuis May 27 '14 at 13:49
5

The constructor of TFrame looks like this:

constructor Create(AOwner: TComponent); virtual;

If you want to override it you must keep the signature:

constructor Create(AOwner: TComponent); override;

If you want to add your own version providing a name you need to overload it so that both versions exist side by side:

constructor Create(name: string); reintroduce; overload; // see Edit below 

If you want to hide the virtual one you need to write reintroduce (not recommended):

constructor Create(name: string); reintroduce;

Edit: reintroduce is also needed when you overload a virtual method even without hiding it. This has been reported and discussed here: http://qc.embarcadero.com/wc/qcmain.aspx?d=106026

Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102
  • 3
    Please don't recommend `reintroduce`. It breaks the ability to polymorphically change the behaviour of subclasses as intended by the base class. The option was only added to resolve name conflicts when a new version of a [library added methods to existing](http://stackoverflow.com/a/742112/224704) base classes. Even that purpose is a little ill-conceived because it only really hides a potential future problem. However, when working on a brand new subclass, here is absolutely no reason not to simply choose different names and avoid the potential problems altogether. – Disillusioned May 22 '14 at 13:11
  • 1
    I did not recommend anything I just listed the different modifiers and what they are for. But I agree regarding breaking polymorphism as this violates the OCP and LSP. – Stefan Glienke May 22 '14 at 14:04
  • You did not recommend it, but you presented the option without also presenting the downsides. – David Heffernan May 22 '14 at 17:46
  • I would venture to suggest that when an expert, like yourself, "just _mentions_" an option: beginners will take that to be a recommendation. – Disillusioned May 22 '14 at 18:17
  • Note that [QualityCentral has now been shut down](https://community.embarcadero.com/blogs/entry/quality-keeps-moving-forward), so you can't access `qc.embarcadero.com` links anymore. If you need access to old QC data, look at [QCScraper](http://www.uweraabe.de/Blog/2017/06/09/how-to-save-qualitycentral/). – Remy Lebeau Jun 09 '17 at 17:51
0

Why don't you simply use OnCreeate event instead of trying to override default Constructor method.

In your case OnCreate event would be enough since you are not making any critical changes to the TFrame component itself but only to other components that have been placed on it.

SilverWarior
  • 7,372
  • 2
  • 16
  • 22
  • Because TFrame has no onCreate event. – CiucaS May 26 '14 at 11:10
  • How would you specify the string value to use in the OnCreate event? Also `OnCreate` gives you a sort of chicken-and-egg problem: Until you've created something, you cannot hook the "OnCreate", but then it's too late to do something when it's created. The only reason it works in DFMs is because it's built into the streaming mechanism. In which case why not simply stream the correct value for the caption? – Disillusioned May 26 '14 at 12:44