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;
Related
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.
This question already has answers here:
How can free Interface implemented class?
(2 answers)
Closed 8 years ago.
I opened a similar topic before, but I had no clear reason for error "invalid pointer operation" when trying to free the class instance. Now I already know the reason so I open a new topic, to expose the problem.
So the reason for this error is when instantiating the class ChatClient and pass as a parameter the instance of the class itself (TChatManager). Probably the problem is related to the implementation of the class TChatManager to the interface.
Interface:
Type
// An interface definition
IMessageEvents = Interface(IInterface)
['{BD27EFC6-CC9A-437A-A8B8-16F722518836}']
Procedure messageReceived(messageData: String);
End;
Class TChatManager:
Type
TChatManager = Class(TInterfacedObject, IMessageEvents)
Private
cChatClient: TChatClient;
Protected
Procedure messageReceived(messageData: String); Overload;
Public
Constructor Create; Overload;
Destructor Destroy; Override;
End;
Implementation
Constructor TChatManager.Create;
Begin
Inherited Create;
self.cChatClient := TChatClient.Create(self); // self class instance as parameter
End;
Procedure TChatManager.messageReceived(messageData: String);
Begin
End;
Destructor TChatManager.Destroy;
Begin
Inherited Destroy;
End;
Class TChatClient:
Type
TChatClient = Class(TObject)
Private
iMsgEvents: IMessageEvents;
Protected
Public
Constructor Create(iMsgEvents: IMessageEvents); Overload;
Destructor Destroy; Override;
End;
Implementation
Constructor TChatClient.Create(iMsgEvents: IMessageEvents);
Begin
Inherited Create;
self.iMsgEvents := iMsgEvents;
End;
Destructor TChatClient.Destroy;
Begin
Inherited Destroy;
End;
Main:
cChatManager: TChatManager;
self.cChatManager := TChatManager.Create;
self.cChatManager.Free; // Failed
Anyone can explain what I'm implementing bad? Thanks.
NOTE: The classes are not complete, i deleted some methods where release objects, etc...
Regards.
The answer to your question is the following method of TInterfacedObject:
procedure TInterfacedObject.BeforeDestruction;
begin
if RefCount <> 0 then
Error(reInvalidPtr);
end;
Your code is destroying the TChatManager instance having nonzero RefCount field because it is referenced by the TChatClient instance.
The OP code cannot be fixed and should be redesigned because in the current form the TChatManager instances should be destroyed in TChatClient destructor (by setting iMsgEvents:= nil) and this is weird! :)
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;
I'm hoping to create something like a "TOwnedStringList" (class name is a fiction) that I could construct as:
sl := TOwnedStringList.Create(Self);
sl.Sorted := True;
sl.Duplicates := dupIgnore;
sl.Add(...);
// etc...
Where Self could be a Form (for example), so that the Owner will auto free the StringList.
I want to be able to avoid calling sl.Free myself.
Is This possible?
That's going to be a little messy. You'd need to do something like this.
type
TOwnerComponent = class(TComponent)
private
FOwnedObject: TObject;
public
constructor Create(Owner: TComponent; OwnedObject: TObject);
destructor Destroy; override;
end;
TOwnedStringList = class(TStringList)
private
FOwner: TOwnerComponent;
public
constructor Create(Owner: TComponent);
destructor Destroy; override;
end;
{ TOwnerComponent }
constructor TOwnerComponent.Create(Owner: TComponent; OwnedObject: TObject);
begin
inherited Create(Owner);
FOwnedObject := OwnedObject;
end;
destructor TOwnerComponent.Destroy;
begin
FOwnedObject.Free;
inherited;
end;
{ TOwnedStringList }
constructor TOwnedStringList.Create(Owner: TComponent);
begin
inherited Create;
if Assigned(Owner) then
FOwner := TOwnerComponent.Create(Owner, Self);
end;
destructor TOwnedStringList.Destroy;
begin
if Assigned(FOwner) and not (csDestroying in FOwner.ComponentState) then
begin
FOwner.FOwnedObject := nil;
FOwner.Free;
end;
inherited;
end;
Basically you create an instance of TOwnerComponent that is owned by the Owner that you pass to TOwnedStringList.Create. When that Owner dies, it destroys the TOwnerComponent which in turn destroys your string list.
The code is resilient to an explicit Free being called on the string list.
Imagine I have a class: TCantBeDestroyed
Some one knows how to create a kind of instance that can't be destroyed in both cases, directly:
CantBeDestroyed.Free;
CantBeDestroyed.Destroy;
And can't be destroyed by cast:
TObject(CantBeDestroyed).Free;
TObject(CantBeDestroyed).Destroy;
Tks.
You can't stop anyone calling a destructor or Free, but you can make sure that doing so has no effect:
type
TCannotBeDestroyed = class
public
destructor Destroy; override;
procedure BeforeDestruction; override;
procedure FreeInstance; override;
end;
destructor TCannotBeDestroyed.Destroy;
begin
//don't call inherited
end;
procedure TCannotBeDestroyed.BeforeDestruction;
begin
//don't call inherited
end;
procedure TCannotBeDestroyed.FreeInstance;
begin
//don't call inherited
end;
I can't imagine why you would want to do this though!