Can it make sense to call one overloaded constructor from another? - delphi

If I have two overloaded constructors, one without and one with parameters:
constructor Create; overload;
constructor Create(Param: TObject); overload;
If I want the code in the first one to run, does it make sense to call it within the second one? And inherited to call the parent constructor first as well?
constructor TMyType.Create(Param: TObject);
begin
inherited Create;
Create;
FParam := Param;
end;
Thanks!

If I want the code in the first one to run, does it make sense to call it within the second one And inherited to call the parent constructor first as well?
No. Because your 1st constructor should call inherited one itself, so in the end the inherited constructor would get called twice, which it most probably does not expect.
Otherwise, if your parameterless TMyType.Create() does not call inherited one, then it is hardly a proper constructor and should be just removed.
So the correct approach would be like that:
constructor TMyType.Create(Param: TObject); overload;
begin
Create();
FParam := Param;
end;
constructor TMyType.Create(); overload;
begin
inherited Create(); // for both constructors
...some common code
end;
However in Delphi there is yet another possibility.
constructor Create; overload;
constructor Create(Param: TObject); overload;
procedure AfterConstruction; override;
constructor TMyType.Create(Param: TObject);
begin
inherited Create();
FParam := Param;
end;
constructor TMyType.Create();
begin
inherited ;
... maybe some extra code
end;
procedure TMyType.AfterConstruction();
begin
inherited;
...some common code
end;
Note the difference though, when would "common code" be executed and when would do "FParam := Param;"
In the 1st way, the flow would be like
Create (Param)
..Create()
....Inherited Create()
....Common Code
..FParam := Param;
AfterConstruction (empty)
In the second the sequence would be different
Create(Param) or Create()
..Inherited Create()
..FParam := Param;
AfterConstruction
..Common Code
As you can see the order of those chunks being executed got reversed.
However maybe you don't need multiple constructors at all?
constructor TMyType.Create(const Param: TObject = nil);
begin
inherited;
... Some code
FParam := Param;
end;

Yes your code makes perfect sense and the constructor's calls do exactly what one should expect.
Delphi object model supports both constructors that call inherited constructors and constructors that do not call inherited ones.
If you are not sure try this:
program Project5;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TMyBase = class
constructor Create;
end;
TMyType = class(TMyBase)
constructor Create; overload;
constructor Create(Param: TObject); overload;
end;
constructor TMyBase.Create;
begin
Writeln('TMyBase.Create');
end;
constructor TMyType.Create;
begin
Writeln('TMyType.Create');
end;
constructor TMyType.Create(Param: TObject);
begin
inherited Create;
Create;
Writeln('TMyType.Create(Param)');
end;
begin
TMyType.Create(TObject.Create);
Readln;
end.

Related

How can I initialize my custom IdIOHandler fields?

This is blowing my mind... I just want to make a new IdIOHandler, and, as usual, I need to do some initialization in the constructor... Normally, I override the constructor of the base class, but this TIdIOHandlerStack which I inherit from, is far from "normal" ! It has no constructor to override, and is not known (to me) how it is created.
TIdEnhancedIOHandler = class(TIdIOHandlerStack)
private
FSendBuffer: TIdBytes;
FSendBuff: TDataStream;
public
constructor Create; // <-- I tested all the variations here, but non of them work
destructor Destroy; override;
end;
implementation
constructor TIdEnhancedIOHandler.Create;
begin
inherited Create;
FSendBuff:= TDataStream.Create(#SendBuffer);
end;
destructor TIdEnhancedIOHandler.Destroy;
begin
FSendBuff.Free;
inherited;
end;
initialization
TIdEnhancedIOHandler.SetDefaultClass;
Where should I put my intitialization code so that it is executed when a new instance of TIdEnhancedIOHandler is created BY DEFAULT in all Indy Components which use IOHandlers ?
I found it... It was the InitComponent method that I must override.
TIdEnhancedIOHandler = class(TIdIOHandlerStack)
private
FSendBuffer: TIdBytes;
FSendBuff: TDataStream;
public
procedure InitComponent; override;
destructor Destroy; override;
end;
implementation
procedure TIdEnhancedIOHandler.InitComponent;
begin
inherited;
FSendBuff:= TDataStream.Create(#SendBuffer);
end;

Delphi: How to overload the parent constructor in a descendant but hide it on other different descendant

I read this answer about constructors and its directives (reintroduce, overload, virtual, override, etc.) but I can't reach the goal I want. Check the following pseudo-code (I mean the code without any directive yet):
TBaseClass = class
constructor Create;
end;
TStringStuff = class (TBaseClass)
constructor Create(str: string);
end;
TNumberStuff = class (TBaseClass)
constructor Create(num: integer);
constructor Create(num: decimal);
end;
I want a TStringStuff object can be created using its own constructor and the parent one:
var
StrStuff: TStringStuff;
begin
StrStuff:=TStringStuff.Create();
//or
StrStuff:=TStringStuff.Create('bla');
end;
but I also want a TNumberStuff object can be created using ONLY its own constructors, i.e. if someone use my library he wont be able to create a TNumberStuff without parameter:
var
NumStuff: TNumberStuff ;
begin
NumStuff:=TNumberStuff.Create(10);
//or
NumStuff:=TNumberStuff.Create(10.5);
// but NOT: NumStuff:=TNumberStuff.Create();
end;
So how to use the directives to achieve my goals?
(I am using Delphi 10.2 Tokyo)
For a variety of reasons you can't achieve exactly what you want, but this is as close as you can get.
I have introduced a 'superbase' class if you like with a hidden constructor, only visible in that unit. The only function of TBaseClass now is to 'expose' the constructor so that you can create instances of TBaseClass.
unit Test1;
interface
type
TBaseBaseClass = class
// This does all the work of TBaseClass, but hides the contructor
private
constructor Create; reintroduce; // this can only be accessed within this unit
end;
TBaseClass = class(TBaseBaseClass)
// a creatable class. No actual work is done here. It's only purpose is to
// 'expose' the base constructor
public
constructor Create; reintroduce;
end;
TStringStuff = class( TBaseBaseClass )
public
constructor Create; reintroduce; overload;
constructor Create( str : string ); reintroduce; overload;
end;
TNumStuff = class( TBaseBaseClass )
public
constructor Create( num : integer ); reintroduce; overload;
constructor Create( num : single ); reintroduce; overload;
end;
implementation
{ TStringStuff }
constructor TStringStuff.Create(str: string);
begin
inherited Create;
// ...
// other stuff
end;
constructor TStringStuff.Create;
begin
inherited Create;
// does no extra work! 'exposes' TBaseBaseClass constructor
// but required because of rules of polymorphism
end;
{ TBaseBaseClass }
constructor TBaseBaseClass.Create;
begin
inherited Create;
// ...
// other stuff - does the work originally in TBaseClass
end;
{ TBaseClass }
constructor TBaseClass.Create;
begin
inherited Create;
// does no extra work! 'exposes' TBaseBaseClass constructor
end;
{ TNumStuff }
constructor TNumStuff.Create(num: single);
begin
inherited Create;
// ...
// other stuff
end;
constructor TNumStuff.Create(num: integer);
begin
inherited Create;
// ...
// other stuff
end;
end.
In another unit, if you put a test procedure like this
procedure Test;
var
iBaseClass : TBaseClass;
iStringStuff : TStringStuff;
iNumStuff : TNumStuff;
begin
iBaseClass := TBaseClass.Create;
iStringStuff := TStringStuff.Create;
iNumStuff := TNumStuff.Create;
end;
you will find it does not compile.
But there are a couple of 'gotchas'. If you try putting this procedure in the same unit as the original definitions it will compile. That is because the TBaseBase constructor is visible within the unit.
The second gotcha is related to the fact that the hidden constructor is parameterless, and there is a public parameterless constructor for TObject, from which all objects are descended. So if you try to create an instance of TBaseBaseClass using a constructor without parameters it will compile. It just won't use the constructor you might expect. It will use the TObject constructor.
Finally I would advise against ever trying to hamstring other programmers. By all means lead them in the right direction, but don't try and stop them doing what they want to do. With that in mind, I would not do it this way. I would make the TBaseBase constructor protected, not private. I am just showing this to answer your question.
Here is how I wold deal with your problem
First I would set BaseClass constructor to be virtual and thus allow overriding it in desendant classes
TBaseClass = class
constructor Create; virtual;
end;
Then in TStringStuff class I would change your existing constructor so that its string parameter is actually an optional parameter. This would allow you to call this constructor with or without string parameter passed to it. So now ony thing you need to do is call parent constructor with the help of inherited when no parameter was passed to consturctor or do necessary work before if string paramter was passed to the constructor.
TStringStuff = class (TBaseClass)
constructor Create(str: string = ''); override;
end;
And in TNumberStuff class you just reintroduce your overloaded constructors to be able to manage multiple posible input parameter types that can be passed to the constructor.
TNumberStuff = class (TBaseClass)
constructor Create(num: integer); reintroduce; overload;
constructor Create(num: decimal); reintorduce; overload;
end;

Memory leak in a delphi with TList<string>

Good day,
I have class
TMn2Adapter = class(TPersistent)
private
FGrid: TStringGridPointer;
FList: TList<string>;
// ...
public
constructor Create(AGrid: TStringGridPointer);
destructor Destroy();
end;
constructor TMn2Adapter.Create(AGrid: TStringGridPointer);
begin
FGrid := AGrid;
FList := TList<string>.Create();
end;
destructor TMn2Adapter.Destroy;
begin
Dispose(FGrid);
FList.Free;
FList := nil;
inherited;
end;
and another one
TMn2Worker = class(TPersistent)
private
FMn2Adapter: TMn2Adapter;
public
constructor Create(AGrid: TStringGridPointer);
destructor Destroy();
end;
constructor TMn2Worker.Create(AGrid: TStringGridPointer);
begin
FMn2Adapter := TMn2Adapter.Create(AGrid);
end;
destructor TMn2Worker.Destroy;
begin
SysUtils.FreeAndNil(FMn2Adapter);
inherited;
end;
procedure TMn2Adapter.Parse;
begin
FList.Clear();
for I := 1 to FLenght do FList.Add((FGrid)^.Cells[2, I]);
end;
Creating TMn2Worker in a form mn2: TMn2Worker, doing some action and onFormClose I free this one mn2.Free. And I get report from Eurekalog about memory leak (see attached image). It seems to me that something strange happen in a parsing TStringGrid`s cell to the TList.
Your destructor is never called because you did not include the override directive. Declare destructors like this:
destructor Destroy; override;
Some of the rest of your code looks dubious, although we can't see enough to be say anything for sure. Unfortunately you removed most of the relevant code. In one of the variants you call FreeAndNil on a reference that you already set to nil. That clearly is somewhat pointless. And in the other you Dispose a pointer that you didn't allocate which smells odd. Finally, it's not obvious why you would have a pointer to a reference type. That usually indicates a misunderstanding of reference type variable assignment.

Delphi customised constructor in TComponent never runs

i am new to delphi and i am creating a component in delphi 6. but i can't get the constructor to run:
unit MyComms1;
...
type
TMyComms = class(TComponent)
public
constructor MyConstructor;
end;
implementation
constructor TMyComms.MyConstructor;
begin
inherited;
ShowMessage('got here');
end;
it doesn't matter what the constructor is called, but this code doesn't run the constructor at all.
edit
by request, here is how the TMyComms class is initialized (this code is in a different file called TestComms.pas):
unit TestComms;
interface
uses MyComms1, ...
type
TForm1 = class(TForm)
MyCommsHandle = TMyComms;
...
procedure BtnClick(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
procedure TForm1.BtnClick(Sender: TObject);
begin
MyCommsHandle.AnotherMyCommsProcedure;
end;
edit 2
reading some of the answers it looks like constructors must be manually called in delphi. is this correct? if so then this is certainly my main error - i am used to php where the __construct function is automatically called whenever a class is assigned to a handle.
Most likely you are not calling TMyComms.MyConstructor to test your unusual called and used constructor. The way marked with // ** would be th most usual.
type
TMyComms = class(TComponent)
public
constructor MyConstructor;
// the usual override;
// constructor Create(Owner:TComponent);override; // **
constructor Create(AOwner:TComponent);overload; override;
constructor Create(AOwner:TComponent;AnOtherParameter:Integer);overload;
end;
constructor TMyComms.Create(AOwner: TComponent);
begin
inherited ;
ShowMessage('got here Create');
end;
constructor TMyComms.Create(AOwner: TComponent; AnOtherParameter: Integer);
begin
inherited Create(AOwner);
ShowMessage(Format('got here Create with new parametere %d',[AnOtherParameter]));
end;
constructor TMyComms.MyConstructor;
begin
inherited Create(nil);
ShowMessage('got here MyConstructor');
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
TMyComms.MyConstructor.Free;
TMyComms.Create(self).Free;
TMyComms.Create(self,1234).Free;
end;
Your code does not follow the Delphi naming guidelines - the constructor should be named Create.
Since you didn't posted the code actually calling the ctor, I guess, that you may not have called it at all. Try to add a button to your form, doubleclick it and add the following code:
procedure TForm1.Button1Click(Sender : TObject)
var comms : TMyComms;
begin
comms := TMyComms.MyConstructor;
comms.Free;
end;
By the way, if you derive from TComponent, you should override constructor with a parameter - otherwise inherited methods may not work properly.
interface
type TMyComms = class(TComponent)
private
protected
public
constructor Create(AOwner : TComponent); override;
end;
implementation
constructor TMyComms.Create(AOwner : TComponent)
begin
inherited Create(AOwner);
// Your stuff
end;
// Somewhere in code
var comms : TMyComms;
begin
comms := TMyComms.Create(nil);
end;
Your custom constructor is not called because you did not call it.
MyComm := TMyComms.MyConstructor;
But you also have an error in your code. Because there is no derived constructor you can inherite with simple inherited.
type
TMyComms = class(TComponent)
public
constructor MyConstructor;
end;
implementation
constructor TMyComms.MyConstructor;
begin
inherited Create( nil ); // !
ShowMessage('got here');
end;
You can use the simple inherited if your custom constructor use the same name and parameters from an existing constructor.
type
TMyComms = class(TComponent)
public
constructor Create( AOwner : TComponent ); override;
end;
implementation
constructor TMyComms.Create( AOwner : TComponent );
begin
inherited; // <- everything is fine
ShowMessage('got here');
end;

How do you override delegated method implementation?

In Delphi 2007, I am using one class to implement one of the supported interfaces of second class. This is working. The Delphi help states:
By default, using the implements keyword delegates all interface
methods. However, you can use methods resolution clauses or declare
methods in your class that implement some of the interface methods to
override this default behavior.
However, when I declare a method in my second class that has the matching signature of one of the interface methods, it isn't getting called.
I wonder if this is because I'm accessing the class through another interface when I create it.
Below is a test program that demonstrates my problem:
program Project1;
{$APPTYPE CONSOLE}
type
IInterface1 = interface
['{15400E71-A39B-4503-BE58-B6D19409CF90}']
procedure AProc;
end;
IInterface2 = interface
['{1E41CDBF-3C80-4E3E-8F27-CB18718E8FA3}']
end;
TDelegate = class(TObject)
protected
procedure AProc;
end;
TMyClass = class(TInterfacedObject, IInterface1, IInterface2)
strict private
FDelegate: TDelegate;
property Delegate: TDelegate read FDelegate implements IInterface1;
public
constructor Create;
destructor Destroy; override;
procedure AProc;
end;
procedure TDelegate.AProc;
begin
writeln('TClassDelegate.AProc');
end;
constructor TMyClass.Create;
begin
inherited;
FDelegate := TDelegate.Create;
end;
destructor TMyClass.Destroy;
begin
FDelegate.Free;
inherited;
end;
procedure TMyClass.AProc;
begin
writeln('TMyClass.AProc');
end;
var
MyObj : IInterface2;
begin
MyObj := TMyClass.Create;
(MyObj as IInterface1).AProc;
end.
When I run this I get as output:
TClassDelegate.AProc
What I want is:
TMyClass.AProc
Any help appreciated.
seems you have to redeclare your method in this way:
TMyClass = class(TInterfacedObject, IInterface1, IInterface2)
strict private
....
procedure test();
public
....
procedure IInterface1.AProc = test;
end;
procedure TMyClass.test;
begin
writeln('TMyClass.AProc');
end;
so IInterface1.AProc for TMyClass is mapped to Test() (not to FDelegate.AProc)
and result is TMyClass.AProc
The documentation explicitly states that the behaviour you see is as designed:
If the delegate property is of a class type, that class and its ancestors are searched for methods implementing the specified interface before the enclosing class and its ancestors are searched.
I guess in the full example you have an interface with multiple methods and are wanting the majority specified by the delegate, and specific ones overridden by the implementing class. I can't see how to achieve that with just one class, but it can be done if you introduce a second class:
program Project1;
{$APPTYPE CONSOLE}
type
IInterface1 = interface
['{15400E71-A39B-4503-BE58-B6D19409CF90}']
procedure AProc;
procedure AnotherProc;
end;
TDelegate = class
protected
procedure AProc;
procedure AnotherProc;
end;
TMyClass = class(TInterfacedObject, IInterface1)
strict private
FDelegate: TDelegate;
property Delegate: TDelegate read FDelegate implements IInterface1;
public
constructor Create;
destructor Destroy; override;
procedure AProc;
end;
TMyOtherClass = class(TMyClass, IInterface1)
procedure IInterface1.AProc = AProc;
end;
procedure TDelegate.AProc;
begin
writeln('TDelegate.AProc');
end;
procedure TDelegate.AnotherProc;
begin
writeln('TDelegate.AnotherProc');
end;
constructor TMyClass.Create;
begin
inherited;
FDelegate := TDelegate.Create;
end;
destructor TMyClass.Destroy;
begin
FDelegate.Free;
inherited;
end;
procedure TMyClass.AProc;
begin
writeln('TMyClass.AProc');
end;
var
MyObj: IInterface1;
begin
MyObj := TMyOtherClass.Create;
MyObj.AProc;
MyObj.AnotherProc;
Readln;
end.
As #teran points out, if you are prepared to rename your method then there is an easier solution.
It might be due to the visibility of the property. Every time I use implements the properties are protected or public, same for all the examples I could find in the VCL (eg TAutoObjectEvent.
Attempt #2:
What happens if you remove the AProc() method from TMyClass? Does it then use the one on TDelegate?
The part of documentation you mentioned seems to be outdated. If you try to use method resolution for an interface which is used in an implements clause you will get compiler error E2264: Cannot have method resolutions for interface '%s'.
The solution shown in the link above - to simply give the procedure the same name as declared in the interface - doesn't seem to work, either, in Delphi XE (it compiles but the procedure is not called).

Resources