How to call functions, which require the control `Parent` to be set, in constructor? - delphi

I have a TCustomControl and I must call in the constructor some functions which require that the control has the Parent property set. I tried to set it first and it's working if I create the instance of the control at run time but when I want to put it on the form at design time I get access violation. How can I fix this ?
constructor TPathHolder.Create(AOwner: TComponent);
begin
inherited;
Parent:=TWinControl(AOwner);
//.....that function here....
end;

Do not assign Parent of control in your constructor (or in any part inside your control code). Setting parent inside control itself interferes with the way VCL framework works in both design and run-time.
Instead you can override SetParent method, and do your initialization there.
procedure SetParent(AParent: TWinControl); override;
procedure TMyControl.SetParent(AParent: TWinControl);
begin
inherited;
// put custom initialization code here
end;
Just keep in mind that this method can be called multiple times during control lifetime, and passed AParent can be nil.

You should not set the Parent in the constructor. It is as simple as that. The Parent should be set after the constructor has returned.
You will need to call these other functions, those that require Parent to be set, later. Or find a way to get the work done without requiring Parent to be set.

Related

Is it ok to initialize members field before inherited in create?

Is it ok to initialize members field before calling inherited in create ?
IE:
constructor TMyObject.create(AOwner: TComponent);
begin
fMyField := xxx;
inherited
end;
instead of normal way :
constructor TMyObject.create(AOwner: TComponent);
begin
inherited
fMyField := xxx;
end;
just to know is their is any drawback i didn't see ...
When an instance of a class is instantiated, the memory is allocated and default initialized (e.g. filled with zeros), and then the constructor is called. So, any code in a constructor executes after the default initialization, which would be the one timing issue that you might imagine scuppering what you are doing.
However, code such as yours is usually indicative of a deeper design malaise. How could it matter whether you initialized a value before calling the inherited constructor? There are two reasons I can imagine where you might be tempted to do this:
If the field in question is declared in your derived class, then the only way the ancestor code could access it is by calling a virtual (or dynamic) method. And doing so in a constructor is dangerous because the object is only partially created. That's a big toxic code smell.
If the field in question is declared in the ancestor classes, you might be using this mechanism to in effect pass an argument from derived class to ancestor. That's a rather weird way of doing it. A much more appropriate way would be to use arguments in your constructor.

Is inherited keyword called automatically in Delphi?

According to this page
http://www.delphibasics.co.uk/RTL.asp?Name=Inherited
It says "It is called at the start of a constructor, and at the end of a desctructor. It is not mandatory, but recommended as good practice. "
Did I not understand correctly this? Does it mean that we don't need to put 'inherited' in constructor or destructor because it will be automatically inserted by compiler?
No, inherited isn't called automatically; you have to do it yourself (if you want to call the inherited procedure, which you normally do). And you can even choose when to do it, see, e.g., this answer. Typically you do it at the beginning of a constructor, and at the end of a destructor.
No, that's not what it means; what it's saying is that you can choose not to call it if you have a reason not to call it. You should almost always call inherited in every method you're overriding, unless you need for something not to happen in your descendant that the parent does.
Unless you have a very good reason not to do so, you should always call inherited as the first line of your constructor, and the last line of your destructor. It is never called automatically.
Delphi makes it very easy; if your overridden method has the same parameters as the parents, you don't even have to pass them on:
constructor TMyClass.Create(AOwner: TComponent);
begin
inherited; // Automatically passes AOwner to parent constructor
// Do other construction here
end;
destructor TMyClass.Destroy;
begin
// Do your own cleanup
inherited;
end;

What's the damage from calling inherited incorrectly?

In searching for a highly intermittent memory corruption in a Delphi XE program, I have found a class constructor which initializes a few fields in the class, and then calls inherited. I believe the initializations were added after the constructor was first written, and accidentally in the wrong place. I have now corrected it to call inherited first. The exceptions from the memory corruption almost always occur in a method of this class.
Question: is it possible that this mistake caused an intermittent memory corruption? In tracing the code, it seems not, but I would really like this fix to be what solves the intermittent issue. That it does not occur for a while after fixing the problem will not prove that it has gone away.
Some code:
Tmyclass = class
ctype : integer;
ts : tstringlist;
th : thandle;
public
Constructor Create;
Destructor Destroy; override;
...
end;
Constructor Tmyclass.Create;
begin
ctype := 3;
doinit;
inherited;
end;
Here are typical steps of an object creation:
Memory allocation of the object instance;
Fill all memory with zero (to initialize all fields, especially string);
Call all nested constructors, beginning with the latest child, letting inherited call every parent - that is why you shall write inherited in both constructors and destructors.
So, inherited calls the parent method - you can even specify a parent level, or call none if you are sure you can do that (but may break the SOLID principles).
In fact, when a constructor is called, there is an hidden parameter added to the method:
Constructors and destructors use the same calling conventions as other
methods, except that an additional Boolean flag parameter is passed to
indicate the context of the constructor or destructor call.
A value of False in the flag parameter of a constructor call indicates
that the constructor was invoked through an instance object or using
the inherited keyword. In this case, the constructor behaves like an
ordinary method. A value of True in the flag parameter of a
constructor call indicates that the constructor was invoked through a
class reference. In this case, the constructor creates an instance of
the class given by Self, and returns a reference to the newly created
object in EAX.
A value of False in the flag parameter of a destructor call indicates
that the destructor was invoked using the inherited keyword. In this
case, the destructor behaves like an ordinary method. A value of True
in the flag parameter of a destructor call indicates that the
destructor was invoked through an instance object. In this case, the
destructor deallocates the instance given by Self just before
returning.
The flag parameter behaves as if it were declared before all other
parameters. Under the register convention, it is passed in the DL
register. Under the pascal convention, it is pushed before all other
parameters. Under the cdecl, stdcall, and safecall conventions, it is
pushed just before the Self parameter.
Source: official Delphi documentation
So you can be sure that, wherever the inherited is called, it will be safely handled. For instance, initialization of fields (reset to 0) will be processed only once, before all constructors are called.
The TObject.Create default constructor (the one called in your inherited line) is just a begin end void block, which does nothing. It is not even necessary/mandatory to call inherited here, but it is a good habit, since if you change your object hierarchy, it may be needed afterall.
Only issue may be if some fields are set inside this inherited method (ctype := 2 e.g.), after having been set in the child - but this is not compiler's fault, this is up to user code!
Initializing some fields before calling the inherited constructor is not necessarily a bug. Sometimes the inherited constructor calls some virtual methods which have been overridden by the descendant and these new implementations rely on those fields to be correctly initialized.
(I am not saying that this is good design, but it's not a bug.)
In Delphi you can initialize object fields before calling inherited constructor (it does not worked in Turbo Pascal or 'old' object model, but it is allowed in Delphi 'new' object model).

Safe way in Delphi for a Form to distribute interface objects tied to its lifetime?

I have a Delphi Form that provides the functionality behind an interface object that other parts of the code get references too via a property belonging to the Form. I can't delegate the interface functionality to a child object because too much of that functionality is serviced by controls/components on the form. I can't use TAggregatedObject or TContainedObject to link the lifetime of the interfaced objects being passed around to the Form because the TForm class does not inherit from TinterfacedObject and Delphi does not support multiple inheritance so I can't mix in TInterfacedObject into the inheritance chain. This situation can lead to access violations if a Form gets destroyed while some other code holds one of the interface references passed out by the Form. Can anyone think of a good solution to this problem?
You can delegate the interface to a child object, just have that object contain an internal pointer to the Form so it can access the Form's controls when needed, no different then you are already doing right now.
You can use TAggregateObject or TContainedObject for your needs. They do not require the Form to derive from TInterfacedObject. All they do require is an IInterface interface pointer, and TComponent derives from IInterface (and overrides the _AddRef() and _Release() to disable reference counting), so you can pass the Form itself (being a TComponent descendant) as the required IInterface pointer.
That leaves the only issue remaining - the Form closing while active interface references are being held by other code. The simpliest solution is to either 1) rewrite that code to not hold on to those references while the Form is closing, or 2) don't allow the Form to close until those references have been released.
Note: This will only work, if your consumer is also derived from TComponent.
To avoid the dead references you can query the IInterfaceComponentReference (available on every TComponent) from your form, call GetComponent on that interface and attach yourself to the FreeNotification of the returned Component/Form.
What happens now is: When the Form gets destroyed it will notify all "listners" that its going to destroy itself by calling the Notification method on the consumer with itself (form) as AComponent and opRemove as operation. Thus allowing you to nil your interface reference.
But be aware that the object references and interface references must not be equal.
Also make sure to call RemoveFreeNotification when you don't need the Notification any more to avoid unnecessary calls.
TSomeConsumer = class(TComponent)
private
FInterfaceToAService: ISomeInterface;
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
procedure SetService(const Value: ISomeInterface);
end;
procedure TSomeConsumer.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = TObject(FInterfaceToAService)) then
SetService(nil); // Takes care of niling the interface as well.
end;
procedure TSomeConsumer.SetService(const Value: ISomeInterface);
var
comRef: IInterfaceComponentReference;
begin
if Supports(FInterfaceToAService, IInterfaceComponentReference, comRef) then
comRef.GetComponent.RemoveFreeNotification(self);
FInterfaceToAService := Value;
if Supports(FInterfaceToAService, IInterfaceComponentReference, comRef) then
comRef.GetComponent.FreeNotification(self);
end;

Using inherited in the "Create" constructor of an TObject

Rant: Should I call "inherited" in the constructor of a class derived from TObject or TPersistent?
constructor TMyObject.Create;
begin
inherited Create; // Delphi doc: Do not create instances of TPersistent. Use TPersistent as a base class when declaring objects that are not components, but that need to be saved to a stream or have their properties assigned to other objects.
VectorNames := TStringList.Create;
Clear;
end;
Yes. It does nothing, true, but it's harmless. I think there is value in being consistent about always calling the inherited constructor, without checking to see if there is, in fact, an implementation. Some will say that it's worth calling inherited Create because Embarcadero might add an implementation for TObject.Create in the future, but I doubt this is true; it would break existing code which does not call inherited Create. Still, I think it is a good idea to call it for the reason of consistency alone.
I always do this.
If you are refactoring and move code to a common ancestor, calling the inherited Create has the following advantages:
If the common ancestor has a constructor, you can't forget to call it.
If the common ancestor has a constructor with different parameters, the compiler warns you for this.
You can also override "procedure AfterConstruction". This procedure is always called, no matter what kind of constructor.
public
procedure AfterConstruction; override;
end;
procedure TfrmListBase.AfterConstruction;
begin
inherited;
//your stuff, always initialized, no matter what kind of constructor!
end;
For example: if you want to create an object with a different constructor than the normal TObject.Create, such as TComponent.Create(AOwner) or a custom (overloaded) constructor, you can get problems because your override is not called and (in this case) your "VectorNames" variable will be nil.
I call it, except when i need a very optimized constructor.

Resources