Override construct error - delphi

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?

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.

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

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.

Related

Adding an overload in child class

I have a base class TParent which defines a method without the overload directive:
TParent = class
public
procedure Test();
end;
In a child class TChild, I'm trying to add an overload for the Test procedure.
TChild = class(TParent)
public
procedure Test(AParam : Integer);
end;
On compiling there are no errors neither warnings but if I try to use the TParent.Test with a TChild instance, it gives an E2035 error, like if the parent method was hidden by the child's one:
var
Obj : TChild;
begin
Obj := TChild.Create;
try
Obj.Test();
finally
Obj.Free;
end;
end;
[dcc32 Error] Unit1.pas(52): E2035 Not enough actual parameters
In order to resolve the compiling error, I have to add the overload directive to the TChild.Test declaration.
TChild = class(TParent)
public
procedure Test(AParam : Integer); overload;
end;
It compiles and seems to work, but is it correct even if the TParent.Test declaration has no overload directive at all? Or should I change the name of the child's procedure in case the parent class has not predicted the method to be overloaded?
I believe this is perfectly OK.
The documentation on overloading methods (as opposed to simply overloading non-method procedures and functions) states
A method can be redeclared [in a descendant class (my remark)] using the overload directive. In this case, if the redeclared method has a different parameter signature from its ancestor, it overloads the inherited method without hiding it. Calling the method in a descendent class activates whichever implementation matches the parameters in the call.
This is the only description given, and it isn't crystal clear. Still, the most reasonable interpretation is that it is perfectly fine to do what you suggest. The fact that it works and is used in a lot of existing Delphi source code I think settles it.

What is this “cyclic inheritance” called in Delphi?

I saw a code like this the other day:
type
TcxGridTableControllerAccess = class (TcxGridTableController);
TMycxGridDBTableView = class (TcxGridDBTableView)
protected
function GetViewDataClass: TcxCustomGridViewDataClass; override;
end;
TMycxGridViewData = class (TcxGridViewData)
protected
function GetFilterRowClass: TcxGridFilterRowClass; override;
end;
TMycxGridFilterRow = class (TcxGridFilterRow)
protected
procedure SetValue(Index: Integer; const Value: Variant); override;
end;
TcxGridDBTableView = class (TMycxGridDBTableView);
TMycxGridDBTableView inherited from TcxGridDBTableView that inherited from TMycxGridDBTableView. Searched for Cyclic Inheritance but only Java results.
What is this called?
Ps: I don't have the full buildable code with me.
The example code doesn't do what you think it does. You see TMycxGridDBTableView being defined as a descendant of TcxGridDBTableView, and then you see TcxGridDBTableView, defined as a descendant of TcxGridDBTableView.
However, the TcxGridDBTableView you see at the top is not the same TcxGridDBTableView that you see later. The first one refers to a class declared elsewhere, in some other unit. The next occurrence is declaring a new class in this unit that happens to have the same base name as the other unit's class.
This technique is known as an interposer class. It's used to introduce a new GetViewDataClass method, but still end up with the same class name. The form that uses controls with that name will use the new version of the class instead of the original version. It's a way to customize a VCL control without having to compile and install a custom package.
What you show is not cyclic inheritance. What happens is that dxSample.TMycxGridDBTableView inherits from a TcxGridDBTableView in another unit, probably cxGridDBTableView.TcxGridDBTableView. And dxSample.TcxGridDBtableView inherits from dxSample.TMycxGridDBTableView.
Your code is equivalent to:
type
TcxGridTableControllerAccess = class(TcxGridTableController);
{ Note: this does NOT inherit from the TcxGridDBTableView defined }
{ a little further on in the source. It inherits from the original }
{ DevEx TcxGridDBTableView. }
TMycxGridDBTableView = class(cxGridDBTableView.TcxGridDBTableView)
protected
function GetViewDataClass: TcxCustomGridViewDataClass; override;
end;
TMycxGridViewData = class(TcxGridViewData)
protected
function GetFilterRowClass: TcxGridFilterRowClass; override;
end;
TMycxGridFilterRow = class(TcxGridFilterRow)
protected
procedure SetValue(Index: Integer; const Value: Variant); override;
end;
TcxGridDBTableView = class(TMycxGridDBTableView);
So the hierarchy is:
cxGridDBTableView.TcxGridDBTableView
|
v
dxSample.TMycxGridDBTableView
|
v
dxSample.TcxGridDBTableView
So dxSample.TMycxGrdiDBTableView does not inherit from dxSample.TcxGridDBTableView, but from cxGridDBTableView.TcxGridDBTableView instead, so there is no so called cyclic inheritance there. The whole misunderstanding comes from the fact that the two classes in the different units have the same name and that the first declaration does not fully qualify the class it is inheriting from.
Now, if someone puts the unit dxSample after cxridDBTableView in his or her uses clause, then dxSample.TCxGridDBTableView is used, instead of the original DevEx class. This is called interposing.
When people want to modify the behaviour of the VCL and FireMonkey, it is not unusual to see interposer classes like
type
TVCLClass = class(OriginalVCLUnit.TVCLClass)
// modifications to the original TVCLClass
end;
or
type
TMyVCLClass = class(OriginalVCLUnit.TVCLClass)
//
end;
TVCLClass = class(TMyVCLCLass);
The code you showed does the latter.

Component property not considered on runtime in Delphi XE2

I am developing a component but I can't make it consider a property set at design-time.
The following is an excerpt of the component:
TRVEditFrame = class(TFrame)
...
private
{ Private declarations }
FRVEditor:TCustomRichView;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
protected
function GetRVEditor:TCustomRichView;
procedure SetRVEditor(Editor:TCustomRichView);
published
property RVEditor:TCustomRichView read GetRVEditor write SetRVEditor;
end;
...
constructor TRVEditFrame.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
SetRVEditor(FRVEditor);
...
end;
function TRVEditFrame.GetRVEditor:TCustomRichView;
begin
Result:=FRVEditor;
end;
procedure TRVEditFrame.SetRVEditor(Editor:TCustomRichView);
begin
if Assigned(Editor) then begin
FRVEditor:=Editor;
end;
end;
I can register the component, place it in ther form and set FRVEditor on design-time.
Problem is when I run the application the code inside SetRVEditor() is not executed because Editor=nil.
If I was able to set FRVEditor on design-time, how come that it is=nil on run time ? How can I fix this ?
I add here my further comments because the explanation is too long
#Kenneth, thank you for your reply
TCustomRichView is part of a third part component set that manages
hypertext documents and has 4 more specialized descendents and you
are right, TCustomRichView shouldn't be used in a real application.
TRVEditFrame is the component I am developing.
The idea behind my component is to create one single frame (hence the choice of the component TFrame) with menus, shortcuts, popup menus etc to manage each of the 4 TCustomRichView descendents.
This is exactly the reason why I use TCustomRichView: I can "slot" any of the 4 descendents into my component-frame. This is the same principle of TDatasource that can be connected with TTAble and TQuery (they have the same ancestor).
I suppose the reason why the VCL doesn't link RVEditor to the TCustomRichView descendent I set on design-time is because TFrame has no OnCreate event, like TForm for instance.
So far I managed to solve the issue by calling TRVEditFrame.SetRVEditor manually in the TForm.OnCreate that hosts TRVEditFrame but I was wondering if there are better methods to do so and that is why I have asked advice here.
I know you can create a OnCreate event for TFrames as well, maybe I can place TRVEditFrame.SetRVEditor in there but, again, I was wondering if there was a better method.
Regarding the last part of your comment, I am aware of the register procedure but take into account the component is under development. When I develope components I never install them in the IDE because I prefer to keep the test stuff outside the "official" one.
I use this method and as soon as the component is ready then I register it with the procedure you mention. If I want to implement other features to the same component I can work on the test ones and keep on using the "official" one I have in the IDE at the same time.
My suggestion is to change the design in order to get the frame component referencing the custom editor by using the Notification method, instead of manually setting a property. So, change your frame class to
TRVEditFrame = class(TFrame)
...
private
{ Private declarations }
FRVEditor: TCustomRichView;
protected
procedure Notification(aComponent: TComponent; aOperation: TOperation); override;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
public
property RVEditor:TCustomRichView read FRVEditor;
end;
The implementation of the Notification method does the magic of connecting/disconnecting the frame to the custom editor
procedure TRVEditFrame.Notification(aComponent: TComponent;
aOperation: TOperation);
begin
inherited;
if aComponent is TCustomRichView then
if aOperation=opRemove then begin
if aComponent=FRVEditor then
FRVEditor := nil;
end else
FRVEditor := TCustomRichView(aComponent);
end;
I don´t know if you need any special handling when an editor is set/reset to the frame, so this code does nothing in special, just assigns the component or nil to the FRVEditor data member at the proper moment.
You should create child components.
constructor TRVEditFrame.Create(AOwner: TComponent);
begin
inherited; // Create(AOwner);
FRVEditor := TRichView.Create(self);
end;
DFM streaming engine may load properties of already created class, but it cannot create the class for you for two reasons:
1) DFM can not know of any special tuning done on created component, like what should be constructor parameters (if any), what constructor to use (of many), which niotifications and event handlers to attach and so on.
2) DFM can not know which type the property should be. For example i published TStrings oroperty - object of which class should be created to feel in ? TStrings? TStringList? TRichEditStringList? THashedStringList ? they all were inherited from TStrings and thus any of them is fine choice for DFM - but not for the ocmponent you write.
Thus DFM streaming subsystem is responsible for saving and loading properties of objects, but creating those object is purely your responsibility.
I believe you also may cut the corners by learning how IDE Designer creates your forms and making RVEdit a variable rather than property:
TRVEditFrame = class(TFrame)
...
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
published
var RVEditor:TCustomRichView; // just like users' forms are created by IDE
end;
Then hopefully TFrame constructor would create the content for this variable for you. But this design is fragile because any outer code would be able by any stupid mistake to make something like MyEditFrame.RVEditor := ... and cause a memory leak and unexpected failures of all the attached connections between the editor and the frame.

Delphi XE: Can I call virtual constructors with parameters from a classtype-constrained generic type without resigning to hacks?

I'm trying to build a generic ancestor for composite controls. The initial idea looked something like this:
type
TCompositeControl<TControl1: TControl; TControl2: TControl> = class(TWinControl)
private
FControl1,
FControl2: TControl;
public
constructor Create(AOwner: TComponent); override;
end;
TLabelAndEdit = TCompositeControl<TLabel, TEdit>; // simple example for illustration only
constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FControl1 := TControl1.Create(Self);
FControl2 := TControl2.Create(Self);
end;
As you might already be aware, this will trigger compiler error E2568: Can't create new instance without CONSTRUCTOR constraint in type parameter declaration. Adding the constructor constraint doesn't help however as it implies a parameter-less constructor.
Casting the templates to TControl makes the code compilable:
...
FControl1 := TControl(TControl1).Create(Self);
...
...but it results in an Access Violation at runtime.
One hack that would probably work is invoking the constructor via RTTI, but I would consider that a rather dirty solution.
Another hack that essentially works is using class type variables as intermediates:
type
TControlClass = class of TControl;
constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent);
var
lCtrlClass1,
lCtrlClass2: TControlClass;
begin
inherited Create(AOwner);
lCtrlClass1 := TControl1;
FControl1 := lCtrlClass1.Create(Self);
lCtrlClass2 := TControl2;
FControl2 := lCtrlClass2.Create(Self);
end;
Is there a cleaner solution? Also, can somebody explain to me why the classtype-constraint does not suffice for invoking the virtual constructor on the type parameter directly?
Your typecast is bad: TControl(TControl1).Create(Self). That tells the compiler that TControl1 is an instance of TControl, but we know that it's not an instance. It's a class reference. Type-cast it to the class-reference type instead:
FControl1 := TControlClass(TControl1).Create(Self);
An alternate syntax is
FControl1 := TControl1(TControl1.NewInstance); // get memory for object
FControl1.Create(self); // call type-specific constructor
FControl2 := TControl2(TControl2.NewInstance); // get memory for object
FControl2.Create(self); // call type-specific constructor
This is used in Delphi's Classes.pas::CreateComponent
I just can't decide which option is the least ugly!
It seems it the latest delphi version (Seattle) this compiler error is not emitted anymore. I had the same issue we an application, but only when compiled with DelphiXe8 not with delphi Seattle
If your Class uses a constructor without parameters (like TObject), I would suggest to do what the compiler says:
"Add a constructor constraint to the type-parameter declaration"
It should look something like this:
TCompositeControl < Control1: TControl, constructor; TControl2: TControl, constructor > = Class(TWinControl)
If you do so, you should be able to make the necessary call to the constructor of the generic Type.
Howether, I don't know, if it works with a constructor, who needs a parameter.
Please let us know, if it works.

How can I detect if a Delphi class has a virtual constructor?

For example, is there a way to find out that this class has a virtual constructor (at runtime)?
TMyClass = class(TObject)
MyStrings: TStrings;
constructor Create; virtual;
end;
For example, in this code I would like to test if the class referenced by Clazz has a virtual constructor:
procedure Test;
var
Clazz: TClass;
Instance: TObject;
begin
Clazz := TMyClass;
Instance := Clazz.Create;
end;
Is there a simple solution, for example using RTTI, which works in Delphi 6 to 2009?
Looking through the TypInfo unit, it doesn't look like there's any way to tell if a method is virtual using RTTI or not. If you have a class reference, though, you can probably roll your own method by examining the VMT.
According to Allen Bauer, in an answer to this question, you can find the end of the VMT immediately before the value pointed to by vmtClassName. The first user-defined virtual method (if any) is found at the address of the class reference. In other words, pointer(Clazz)^. Now that you know the start and end points of the user-defined section of the VMT, it shouldn't be too difficult to make a while loop that compares each pointer in the table against the Code section of a method pointer to Clazz.create casted to a TMethod. If you get a match, then it's a virtual method. If not, then it isn't.
Yes, it's a bit of a hack, but it'll work. If anyone can find a better solution, more power to them.
You know, the more I think about it, the less I like the answer I gave that ended up getting accepted. The problem is, the code as written can only deal with information known at compile-time. If Clazz is defined as a TClass, then putting Clazz.Create in a TMethod is always going to give you a method pointer to TObject.Create.
You could try defining Clazz as a "class of TMyClass". Thing is, you've already got a virtual constructor there, so it's going to give you the highest-level constructor it can reach that overrides that constructor. But from your comments, it looks like what you're trying to find is a non-virtual constructor (using reintroduce;) that will break your virtual construction. Most likely you're using a factory pattern, where this could be an issue.
The only solution to that is to use RTTI to find the constructor that's actually attached to the class. You can get a method pointer for "the method named Create" and use it in the trick I explained in my other answer. To do this, your base virtual constructor has to be declared published. This will force all methods that override it to also be published. Problem is, someone can still use reintroduce; to declare a non-published constructor higher up, and your scheme comes crashing to the ground. You don't have any guarantees about what descendant classes will do.
There's no technical solution to this question. The only thing that really works is education. Your users need to know that this class is instantiated by a factory (or whatever your reason is for needing a virtual constructor) and that if they reintroduce the constructor in a derived class, it could break things. Put a note in the documentation to this effect, and a comment in the source code. That's pretty much all you can do.
Michael,
I get your question, but since your sourcecode does not compile, I think you miss the point of your question ;-)
My answer is a bit of an elaboration on what Mason tried to explain in his second answer.
The issue at hand is that your question imples that you have a 'class reference' (like TClass or TComponentClass) that references to a base class that has a virtual constructor.
However, TClass doesn't (TClass references a class that has a non-virtual constructor), but TComponentClass does.
You see the difference when disassembling the call to the constructor by using a class reference.
When you call a virtual constructor through a class reference, the code is slightly different than when you call a non-virtual constructor:
calling a virtual constructor has an indirection
calling a non-virtual constructor does a direct call
This disassembly shows what I mean:
TestingForVirtualConstructor.dpr.37: ComponentClassReference := TMyComponentClass;
00416EEC A1706D4100 mov eax,[$00416d70]
TestingForVirtualConstructor.dpr.38: Instance := ComponentClassReference.Create(nil); // virtual constructor
00416EF1 33C9 xor ecx,ecx
00416EF3 B201 mov dl,$01
00416EF5 FF502C call dword ptr [eax+$2c]
TestingForVirtualConstructor.dpr.39: Instance.Free;
00416EF8 E8CFCDFEFF call TObject.Free
TestingForVirtualConstructor.dpr.41: ClassReference := TMyClass;
00416EFD A1946E4100 mov eax,[$00416e94]
TestingForVirtualConstructor.dpr.42: Instance := ClassReference.Create(); // non-virtual constructor
00416F02 B201 mov dl,$01
00416F04 E893CDFEFF call TObject.Create
TestingForVirtualConstructor.dpr.43: Instance.Free;
00416F09 E8BECDFEFF call TObject.Free
So when you have a variable of type class reference for which the constructor is virtual, and you call that constructor through that variable, you are sure that the actual class in that variable will have a virtual constructor.
You can not determine on which actual class that constructor is implemented (well, not without extra debugging info, for instance from the .DCU, .MAP, .JDBG, or other sources).
Here is the example code that does compile:
program TestingForVirtualConstructor;
{$APPTYPE CONSOLE}
uses
Classes, SysUtils;
type
TMyComponentClass = class(TComponent)
MyStrings: TStrings;
constructor Create(Owner: TComponent); override;
end;
constructor TMyComponentClass.Create(Owner: TComponent);
begin
inherited;
end;
type
TMyClass = class(TObject)
MyStrings: TStrings;
constructor Create();
end;
constructor TMyClass.Create();
begin
inherited;
end;
procedure Test;
var
// TComponentClass has a virtual constructor
ComponentClassReference: TComponentClass;
ClassReference: TClass;
Instance: TObject;
begin
ComponentClassReference := TMyComponentClass;
Instance := ComponentClassReference.Create(nil); // virtual constructor
Instance.Free;
ClassReference := TMyClass;
Instance := ClassReference.Create(); // non-virtual constructor
Instance.Free;
end;
begin
try
Test;
except
on E: Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
To get back to your original question:
When your class reference references a base class having a virtual constructor, you are sure that you will always call a virtual constructor using an indirection.
When your class reference references a base class having a non-virtual constructor, you are sure that you will always call a non-virtual constructor using a direct call.
Hope this sheds some more light on your question.
--jeroen

Resources