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! :)
Related
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;
This question already has answers here:
Delphi: Method 'Create' hides virtual method of base - but it's right there
(2 answers)
Closed 7 years ago.
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!
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;
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.
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;
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).