Can I have a TCriticalSection object declared as a public field, such as:
type
TMyObject = class
public
CS: TCriticalSection;
end;
I would like to make that field public to allow any thread enter and leave the critical section object, which internally protects integrity of the TMyObject instance. So, can I declare TCriticalSection object as a public class field ?
The simple answer is yes. A field of a class is a perfectly normal place to hold a TCriticalSection.
In order for a critical section to be able to serialize access to a shared resource, all threads must refer to the same instance of the critical section. So, from that fact you conclude that you need to make sure that all threads refer to the same instance of the class. Then when they read the critical section field of that class, all threads are accessing the same instance of the critical section.
It is usually considered to be bad practice to declare public fields. You would normally expose such a thing through either a property, or methods of the class.
This is what I have done in the past to achieve this:
TMyObject = class(TObject)
private
FCS :TCriticalSection;
FMyProp :string;
function GetMyProp :string;
procedure SetMyProp( const NewValue :string );
protected
public
constructor Create;
destructor Destroy; override;
// properties
property MyProp :string read GetMyProp write SetMyProp;
end;
followed by the implementation:
constructor TMyObject.Create;
begin
inherited Create;
FCS := TCriticalSection.Create;
FMyProp := '';
end;
destructor TMyObject.Destroy;
begin
FCS.Free;
inherited Destroy;
end;
function TMyObject.GetMyProp :string;
begin
FCS.Enter;
try
result := FMyProp;
finally
FCS.Leave;
end;
end;
procedure TMyObject.SetMyProp( const NewValue :string );
begin
FCS.Enter;
try
FMyProp := NewValue;
finally
FCS.Leave;
end;
end;
Note that I haven't exposed the FCS field.
Related
I have a class that contains a TObjectList<T> list of objects of another class.
TMyElementClass = class (TPersistent)
private
....
public
....
end;
TMyElemContainerClass = class (TPersistent)
private
fElemList: TObjectList<TMyElementClass>;
...
published
ElemList: TObjectList<TMyElementClass> read fElemList write fElemList;
end;
var
Elements: TMyElemContainerClass;
I register both classes:
System.Classes.RegisterClass (TMyElemContainerClass);
System.Classes.RegisterClass (TMyElementClass);
The problem is, when the Elements object is "saved" to a stream, all of the published fields are correctly saved, but the list itself isn't.
What's wrong?
TObjectList is not a streamable class. Just because you use it in a published property doesn't mean the streaming system automatically knows how to stream it. If you are using the DFM streaming system, only classes that derive from TPersistent are streamable, but TObjectList does not. You will have to implement custom streaming logic for it.
Consider changing your design to use TCollection and TCollectionItem instead, eg:
TMyElementClass = class (TCollectionItem)
private
...
public
...
published
...
end;
TMyElemCollectionClass = class (TCollection)
private
function GetElem(Index: Integer): TMyElementClass;
procedure SetElem(Index: Integer; Value: TMyElementClass);
public
constructor Create; reintroduce;
function Add: TMyElementClass; reintroduce;
function Insert(Index: Integer): TMyElementClass; reintroduce;
property Elements[Index: Integer]: TMyElementClass read GetElem write SetElem; default;
end;
TMyElemContainerClass = class (TPersistent)
private
fElemList: TMyElemCollectionClass;
procedure SetElemList(Value: TMyElemCollectionClass);
...
public
constructor Create;
destructor Destroy; override;
...
published
ElemList: TMyElemCollectionClass read fElemList write SetElemList;
end;
...
constructor TMyElemCollectionClass.Create;
begin
inherited Create(TMyElementClass);
end;
function TMyElemCollectionClass.GetElem(Index: Integer): TMyElementClass;
begin
Result := TMyElementClass(inherited GetItem(Index));
end;
procedure TMyElemCollectionClass.SetElem(Index: Integer; Value: TMyElementClass);
begin
inherited SetItem(Index, Value);
end;
function TMyElemCollectionClass.Add: TMyElementClass;
begin
Result := TMyElementClass(inherited Add);
end;
function TMyElemCollectionClass.Insert(Index: Integer): TMyElementClass;
begin
Result := TMyElementClass(inherited Insert(Index));
end;
constructor TMyElemContainerClass.Create;
begin
inherited;
fElemList := TMyElemCollectionClass.Create;
end;
destructor TMyElemContainerClass.Destroy;
begin
fElemList.Destroy;
inherited;
end;
procedure TMyElemContainerClass.SetElemList(Value: TMyElemCollectionClass);
begin
fElemList.Assign(Value);
end;
Remy gave you one avenue to try.
Another possible way would be implement this list streaming manually.
You would have to
derive your TMyElemContainerClass from TComponent
remove ElemList from published properties
override DefineProperties method that would declare some virtual, not-existing published property to be streamed in and out. You may even name it ElemList or by any other identifier you would see fit. It would be used by Delphi instead your TObjectList object.
implement stream-oriented reader and writer methods for the said virtual property, they should iterate through all the items and save/load them.
Explore documentation from here: http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Classes.TComponent.DefineProperties
See one of many (and there really are many) examples (using arrays rather than lists, but the idea is the same) at How to use DefineProperties in a custom Class Object for Arrays - Delphi
Here is the object:
TCell = class(TPersistent)
private
FAlignmentInCell :byte;
public
constructor Create; virtual;
published
property AlignmentInCell:byte read FAlignmentInCell write FAlignmentInCell;
end;
this is its constructor:
constructor TCell.Create;
begin
inherited;
FAlignmentInCell:=5;
end;
Here is a function, which dynamically creates any object derived form TPersistent (parameter is class name provided as a string)
function CreateObjectFromClassName(AClassName:string):TPersistent;
var DynamicObject:TPersistent;
TempObject:TPersistent;
DynamicPersistent:TPersistent;
DynamicComponent:TComponent;
PersistentClass:TPersistentclass;
ComponentClass:TComponentClass;
begin
PersistentClass:=TPersistentclass(FindClass(AClassName));
TempObject:=PersistentClass.Create;
if TempObject is TComponent then
begin
ComponentClass:=TComponentClass(FindClass(AClassName));
DynamicObject:=ComponentClass.Create(nil);
end;
if not (TempObject is TComponent) then
begin
DynamicObject:=PersistentClass.Create; // object is really TCell, but appropriate constructor seems to be not called.
end;
result:=DynamicObject;
end;
My idea is to create new Cell (TCell) like this:
procedure TForm1.btn1Click(Sender: TObject);
var p:TPersistent;
begin
p := CreateObjectFromClassName('TCell');
ShowMessage(IntToStr(TCell(p).AlignmentInCell)); // it is 0. (Why?)
end;
When I want to check AlignmentInCell property I get 0, but I expected 5. Why? Is there way to fix it?
This is similar to a recent question.
You use TPersistentClass. But TPersistent does not have a virtual constructor, so the normal constructor for TPersistent is called, which is the constructor it inherits from TObject.
If you want to call the virtual constructor, you will have to declare a
type
TCellClass = class of TCell;
Now you can modify CreateObjectFromClassName to use this metaclass instead of TPersistenClass, and then the actual constructor will be called.
Also, TempObject is never freed. And instead of is, I would rather use InheritsFrom.
I did not test the following, but it should work:
function CreateObjectFromClassName(const AClassName: string; AOwner: TComponent): TPersistent;
var
PersistentClass: TPersistentclass;
begin
PersistentClass := FindClass(AClassName);
if PersistentClass.InheritsFrom(TComponent) then
Result := TComponentClass(PersistentClass).Create(AOwner)
else if PersistentClass.InheritsFrom(TCell) then
Result := TCellClass(PersistentClass).Create
else
Result := PersistentClass.Create;
end;
The compiler can't know for sure what value your variable of type TPersistentClass will hold at run time. So he assumes that it is exactly that: a TPersistentClass.
TPersistentClass is defined as a class of TPersistent. TPersistent has no virtual constructor, the compiler will therefore not include a call to dynamically look up the address of the constructor in the VMT of the actual class, but a 'hard-coded' call to the only matching constructor TPersistent has: the one it inherits from its base class TObject.
It might be a decision with reasons I don't know, but if you had chosen to define TCell as following
TCell = class(TComponent)
private
FAlignmentInCell: byte;
public
constructor Create(AOwner: TComponent); override;
published
property AlignmentInCell:byte read FAlignmentInCell write FAlignmentInCell;
end;
you wouldn't need TempObject and all the decision making in your CreateObjectFromClassName function (and the possible leaks as pointed out by others):
function CreateObjectFromClassName(AClassName:string): TComponent;
var
ComponentClass:TComponentClass;
begin
ComponentClass:=TComponentClass(FindClass(AClassName));
Result := ComponentClass.Create(nil);
end;
And make sure to manage the Results life-time as it has no Owner.
On the new side of writing classes and have a little problem which I have tried researching but still no answer.
I want to create one instance of a class which creates multiple subclasses which creates subclasses of their own. The idea is to use code like this in main program:
procedure TForm1.Button1Click(Sender: TObject);
var
Temp : Integer;
begin
MainClass := TMainClass.Create(Form1);
Temp := MainClass.SubClass1.SubSubClass1.SomeValue;
end;
The main class looks like this and is created in seperate file:
TMainClass = class(TObject)
private
FSubClass1 : TSubClass1;
public
ValueFromAnySubClass : Integer;
property SubClass1 : TSubClass1 read FSubClass1 write FSubClass1;
procedure SetSomeValueFromMainClass(Value : Integer);
end;
...
...
...
procedure TMainClass.SetSomeValueFromMainClass(Value : Integer);
begin
ValueFromAnySubClass := Value;
end;
The sub class also in seperate file:
TSubClass1 = class(TObject)
private
FSubSubClass1 : TSubSubClass1;
public
property SubSubClass1 : TSubSubClass1 read FSubSubClass1 write FSubSubClass1;
end;
And now for the sub sub class also in seperate file:
TSubSubClass1 = class(TObject)
private
SomeValue : Integer;
function GetSomeValue : Integer;
procedure SetSomeValue(Value : Integer);
public
property SomeValue : Integer read GetSomeValue write SetSomeValue;
end;
...
...
...
procedure TSubSubClass1.SetSomeValue(Value : Integer);
begin
SetSomeValueFromMainClass(Value); <<< Error Here <<<
end;
How do I get to use the functions and procedures from the main class in my sub classes?
You don't need a subclass to use a function from another class. Also your sample code has not used subclasses at all. A proper subclass automatically has access to all public and proteced functions of its ancestors.
As David has already pointed out, there are serious flaws in your intended deisgn.
Furthermore, based on your comment:
The classes all perform vastly different functions but need to write data to a piece of hardware at the end of the day. The data is read from the hardware and kept in memory to work with until its written back to the hardware component once all work is completed. The procedure in the main class takes care of writing real time data to the hardware whenever it is required by any of the subclasses.
to David's answer: you don't need subclasses at all.
All you need is a public method on your hardware class. And for each instance of your other classes to have a reference to the correct instance of your hardware class.
type
THardwareDevice = class(TObject)
public
procedure WriteData(...);
end;
TOtherClass1 = class(TObject)
private
FDevice: THardwareDevice;
public
constructor Create(ADevice: THardwareDevice);
procedure DoSomething;
end;
constructor TOtherClass1.Create(ADevice: THardwareDevice);
begin
FDevice := ADevice;
end;
procedure TOtherClass1.DoSomething;
begin
//Do stuff, and maybe you need to tell the hardware to write data
FDevice.WriteData(...);
end;
//Now given the above you can get two distinct object instances to interact
//as follows. The idea can be extended to more "other class" types and instances.
begin
FPrimaryDevice := THardwareDevice.Create(...);
FObject1 := TOtherClass1.Create(FPrimaryDevice);
FObject1.DoSomething;
//NOTE: This approach allows extreme flexibility because you can easily
// reference different instances (objects) of the same hardware class.
FBackupDevice := THardwareDevice.Create(...);
FObject2 := TOtherClass1.Create(FBackupDevice);
FObject2.DoSomething;
...
end;
The design looks really poor. You surely don't want to have all these classes knowing all about each other.
And any time you see a line of code with more than one . operator you should ask yourself if the code is in the right class. Usually that indicates that the line of code that has multiple uses of . should be in one of the classes further down the chain.
However, if you want to call a method, you need an instance. You write:
procedure TSubSubClass1.SetSomeValue(Value : Integer);
begin
SetSomeValueFromMainClass(Value);
end;
And naturally this does not compile. Because SetSomeValueFromMainClass is not a method of TSubSubClass1. Rather SetSomeValueFromMainClass is a method of TMainClass. So, to call that method, you need an instance of TMainClass.
Which suggests that, if you really must do this, that you need to supply to each instance of TSubSubClass1 an instance of TMainClass. You might supply that in the constructor and make a note of the reference.
Of course, when you do this you now find that your classes are all coupled together with each other. At which point one might wonder whether or not they should be merged.
I'm not saying that merging these classes is the right design. I would not like to make any confident statement as to what the right design is. Perhaps what you need is an interface that promises to implement the setter as a means to decouple things. All I am really confident in saying is that your current design is not the right design.
As far as I know Subclass word is usually using in inheritance concept but the code you wrote are some compound classes. As you may see the constructor of many classes in Delphi have an argument which named AOwner that may be TComponent or TObject or ...
If you define the constructors of your TSubclass1 and TSubSubClass1 like as follow and Change the Owner of classes that you defined as properties to Self in set functions you may access to your TMainClass by typecasting the Owner property.
I changed your code a little to just work as you want, but I suggest change your design.
TSubSubClass1 = class(TObject)
private
FOwner: TObject;
function GetSomeValue:Integer;
procedure SetSomeValue(const Value: Integer);
procedure SetOwner(const Value: TObject);
public
constructor Create(AOwner:TObject);reintroduce;
property Owner:TObject read FOwner write SetOwner;
property SomeValue : Integer read GetSomeValue write SetSomeValue;
end;
TSubClass1 = class(TObject)
private
FSubSubClass1: TSubSubClass1;
FOwner:TObject;
procedure SetSubSubClass1(const Value: TSubSubClass1);
procedure SetOwner(const Value: TObject);
public
constructor Create(AOwner:TObject);reintroduce;
property Owner:TObject read FOwner write SetOwner;
property SubSubClass1 : TSubSubClass1 read FSubSubClass1 write SetSubSubClass1;
end;
TMainClass = class(TObject)
private
FSubClass1: TSubClass1;
procedure SetSubClass1(const Value: TSubClass1);
public
ValueFromAnySubClass : Integer;
constructor Create;
property SubClass1 : TSubClass1 read FSubClass1 write SetSubClass1;
procedure SetSomeValueFromMainClass(Value : Integer);
end;
implementation
{ TSubSubClass1 }
constructor TSubSubClass1.Create(AOwner: TObject);
begin
Owner:=AOwner;
end;
function TSubSubClass1.GetSomeValue: Integer;
begin
Result:=TMainClass(TSubClass1(Self.Owner).Owner).ValueFromAnySubClass;
end;
procedure TSubSubClass1.SetOwner(const Value: TObject);
begin
FOwner := Value;
end;
procedure TSubSubClass1.SetSomeValue(const Value: Integer);
begin
TMainClass(TSubClass1(Self.Owner).Owner).SetSomeValueFromMainClass(Value);
end;
{ TSubClass1 }
constructor TSubClass1.Create(AOwner: TObject);
begin
Owner:=AOwner;
FSubSubClass1:=TSubSubClass1.Create(Self);
end;
procedure TSubClass1.SetOwner(const Value: TObject);
begin
FOwner := Value;
end;
procedure TSubClass1.SetSubSubClass1(const Value: TSubSubClass1);
begin
FSubSubClass1 := Value;
FSubSubClass1.Owner:=Self;
end;
{ TMainClass }
constructor TMainClass.Create;
begin
FSubClass1:=TSubClass1.Create(Self);
end;
procedure TMainClass.SetSomeValueFromMainClass(Value: Integer);
begin
ValueFromAnySubClass := Value;
end;
procedure TMainClass.SetSubClass1(const Value: TSubClass1);
begin
FSubClass1 := Value;
FSubClass1.Owner:=Self;
end;
you must put the proper filename in uses part of implementation.
How can I alter my destructors to handle shared object instances?
Example:
type
TAddress = class
private
FStreet : String;
public
property street: String read FStreet write FStreet;
end;
TContract = class
private
FAddress : TAddress;
public
property address: TAddress read FAddress write FAddress;
destructor Destroy; override;
end;
Array_Of_TContract = array of TContract;
TCustomer = class
private
FContracts : Array_Of_TContract;
public
property contracts: Array_Of_TContract read FContracts write FContracts;
destructor Destroy; override;
end;
implementation
destructor TCustomer.Destroy;
var
I: Integer;
begin
for I := 0 to System.Length(FContracts)-1 do
SysUtils.FreeAndNil(FContracts[I]);
System.SetLength(FContracts, 0);
inherited Destroy;
end;
destructor TContract.Destroy;
var
I: Integer;
begin
SysUtils.FreeAndNil(FAddress);
inherited Destroy;
end;
begin
Try
//address
myAddress := TAddress.Create;
myAddress.street := 'My Street';
//First contract
SetLength(myContracts, Length(myContracts)+1);
FirstContract := TContract.Create;
FirstContract.address := myAddress; //<-
myContracts[0] := FirstContract;
//Second contract
SetLength(myContracts, Length(myContracts)+1);
SecondContract := TContract.Create;
SecondContract.address := myAddress; //<-
myContracts[1] := SecondContract;
//Single customer
myCustomer := TCustomer.Create;
myCustomer.contracts := myContracts;
myCustomer.Free;
self.Close;
Except
On e: exception do begin
ShowMessage(e.Message);
end;
End;
end;
The result is an invalid pointer operation when freeing myCustomer (and memory leak).
(Creating a separate TAddress object for each TContract is not an option in my case)
The best way to handle this kind of situation depends on the structure of your application. Based on the example I would add all the adresses to a generic objectlist and then pass the address reference to the instance of TContract. For contracts you could use similar approach if they aren't unique.
Alternative is to use interface for the address and then just assign it to the contract instance and finally nil it.
The third option is to copy on assignment. I think that this is the most inefficient way to handle this situation but it's quaranteed to work in every situation.
Hopefully these gave some ideas.
I would prefer not to share the same address instance between contacts. But since code is auto-generated, I guess this is not an option.
You could keep track of already freed references:
AlreadyFreed := TList <Pointer>.Create;
for I := 0 to System.Length(FContracts)-1 do
begin
if not AlreadyFreed.Contains(FContracts[I]) then
begin
FContracts[I].Free;
AlreadyFreed.Add(Pointer(FContracts[I]));
end;
end;
I have the following problem: I've got an entity class 'TEntity' and a mesh class 'TMesh' and TEntity needs to know when its element, (TMesh) is removed. Is there a possible working way I can call the TEntity method 'OnMeshRemove' from the TMesh destructor?
//uTEntity
interface
uses
uTMesh;
type
TEntity = class
Mesh : TMesh;
constructor Create(); overload;
procedure OnMeshRemove();
end;
implementation
constructor TEntity.Create();
begin
Mesh := TMesh.Create();
Mesh.EntityContainer := #self;
end;
procedure TEntity.OnMeshRemove();
begin
//Do stuff
end;
end.
//uTMesh
interface
type
TMesh = class
EntityContainer : Pointer;
destructor Remove();
end;
implementation
uses
uTEntity;
destructor TMesh.Remove();
var
PEntity : ^TEntity;
begin
PEntity := EntityContainer;
if Assigned( PEntity^ ) then
begin
PEntity^.OnMeshRemove();
end;
inherited Destroy();
end;
Example:
var
Ent : TEntity;
begin
Ent := TEntity.Create();
Ent.Mesh.Remove();
//I want Ent.OnMeshRemove to be called. In my example code, there is a pointer problem. I need to solve that. Thanks!
end;
PS: I don't want to have a TEntity procedure like TEntity.RemoveMesh();
All objects in Delphi are pointer type so no need to deference it. Here is a bit more simpler
type
TEntity = class
public
Mesh: TMesh;
constructor Create;
destructor Destroy; override;
end;
implementation
constructor TEntity.Create;
begin
inherited Create;
Mesh := TMesh.Create;
Mesh.EntityContainer := Self;
end;
procedure TEntity.Destroy;
begin
if Mesh <> nil then
begin
Mesh.EntityContainer := nil;
FreeAndNil(Mesh);
end;
inherited Destroy;
end;
//***************************************************
type
TMesh = class
EntityContainer: TObject;
destructor Destroy; override;
end;
implementation
uses
uTEntity;
destructor TMesh.Destroy;
begin
if (EntityContainer <> nil) and (TEntity(EntityContainer).Mesh = Self) then
TEntity(EntityContainer).Mesh := nil;
EntityContainer := nil;
inherited Destroy;
end;
Your TEntity instance should register itself with TMesh instance so that when TMesh instance is being freed, it will modify the TEntity instance about it.
If your classes are derived from TComponent class, then this mechanism is already implemented for you; each TComponent instance has a method called FreeNotification and a method called Notification. Any TComponent instance can register itself with the other component calling its FreeNotification method and passing itself as the parameter. Whenever a component is being destroyed, it will check the list of components registered for its free notification, and will invoke Notification method of each registered component. This way, the register component will be notified whenever the other component is about to be destroyed.
If one TComponent instance is the owner of the other (In your case, TEntity can be the owner of TMesh instance), then it will be notified automatically whenever TMesh instance is removed. All you need to do is to override its Notification method and do whatever you want to do inside that method.
If you do not want to derive your classes from TComponent class or for any reason do not want to use Delphi's implementation, you can implement the same behavior in your own classes. You need an internal list in your TMesh class which holds a list of classes which should be notified. You also need a method to register a class with your TMesh class, and eventually you need a method in your TEntity class which should be called by TMesh whenever it is being freed.
Here is a simple source code just for demonstrating the general idea. Take note that this sample code is not thread-safe, and might lack some other checks. I just wrote it fast to show you how to implement such an idea:
unit Unit1;
interface
uses
Classes, Generics.Collections;
type
TBaseClass = class
private
FNotificationList : TList<TBaseClass>;
protected
procedure Notify(AClass: TBaseClass); virtual;
public
procedure RegisterForNotification(AClass: TBaseClass);
procedure UnregisterNotification(AClass: TBaseClass);
constructor Create;
destructor Destroy; override;
end;
TMesh = class(TBaseClass)
end;
TEntity = class(TBaseClass)
private
FMesh : TMesh;
FOnMeshRemoved : TNotifyEvent;
procedure SetMesh(Value: TMesh);
protected
procedure Notify(AClass: TBaseClass); override;
procedure DoMeshRemoved; virtual;
public
constructor Create;
destructor Destroy; override;
property Mesh : TMesh read FMesh write SetMesh;
property OnMeshRemoved : TNotifyEvent read FOnMeshRemoved write FOnMeshRemoved;
end;
implementation
{ TBaseClass }
constructor TBaseClass.Create;
begin
inherited;
FNotificationList := TList<TBaseClass>.Create;
end;
destructor TBaseClass.Destroy;
var
AClass: TBaseClass;
begin
if Assigned(FNotificationList) then
begin
if (FNotificationList.Count > 0) then
for AClass in FNotificationList do
AClass.Notify(Self);
FNotificationList.Free;
FNotificationList := nil;
end;
inherited;
end;
procedure TBaseClass.Notify(AClass: TBaseClass);
begin
end;
procedure TBaseClass.RegisterForNotification(AClass: TBaseClass);
begin
if not Assigned(AClass) then
Exit;
if FNotificationList.IndexOf(AClass) < 0 then
FNotificationList.Add(AClass);
end;
procedure TBaseClass.UnregisterNotification(AClass: TBaseClass);
begin
if not Assigned(AClass) then
Exit;
if FNotificationList.IndexOf(AClass) >= 0 then
FNotificationList.Remove(AClass);
end;
{ TEntity }
constructor TEntity.Create;
begin
inherited;
end;
destructor TEntity.Destroy;
begin
if Assigned(FMesh) then
FMesh.UnregisterNotification(Self);
inherited;
end;
procedure TEntity.DoMeshRemoved;
begin
if Assigned(FOnMeshRemoved) then
FOnMeshRemoved(Self);
end;
procedure TEntity.Notify(AClass: TBaseClass);
begin
inherited;
FMesh := nil;
DoMeshRemoved;
end;
procedure TEntity.SetMesh(Value: TMesh);
begin
if Assigned(FMesh) then
begin
FMesh.UnregisterNotification(Self);
FMesh := nil;
end;
if Assigned(Value) then
begin
FMesh := Value;
FMesh.RegisterForNotification(Self);
end;
end;
end.
In this code, both TEntity and TMesh are derived from TBaseClass which provides notification mechanism. TEntity does not create any instance of TMesh initially, but you can assign a created TMesh instance to its Mesh property. Doing so will make TEntity to assign that value to its FMesh field, and call its RegisterForNotification class so that it can be notified if the mesh is being destroyed.
When the mesh is being destroyed, it iterates over all the objects registered themselves with it, and invokes their Notify method. Here it would be Notify method of TEntity class. Inside Notify method of TEntity, it first makes its FMesh field nil, because that object is being destroyed and there is no need to keep a reference of a dead object. It then calls DoMeshRemove method which is an event-invoker for OnMeshRemove event.
Edit: back behind a PC.
The classic way of maintaining lists of predetermined objects of a certain class is using TCollection/TCollectionItem.
TCollection/TCollectionItem are heavily used in Delphi (see this list).
They are lighter weight than TComponent (that automatically maintains Owner/Components/ComponentCount and has FreeNotification), as TCollectionItem and TCollection both descend from the TPersistent branch in stead of TComponent branch.
TCollection has a nice virtual Notify method:
procedure TCollection.Notify(Item: TCollectionItem; Action: TCollectionNotification);
begin
case Action of
cnAdded: Added(Item);
cnDeleting: Deleting(Item);
end;
end;
From Delphi 2009, you have generics, so then it can pay off big time to use TList (in your cast TList<TEntity>, as it contains this very nice Notify method and OnNotify event:
procedure TList<T>.Notify(const Item: T; Action: TCollectionNotification);
begin
if Assigned(FOnNotify) then
FOnNotify(Self, Item, Action);
end;
These two solutions work well if your TMesh is indeed a collection/list of TEntity.
If it TMesh is a non-list graph of TEntity, then it is better to descend both from TComponent like vcldeveloperlink text explained in his answer.
Andy Bulka has a nice blog post on the various ways of using lists and collections, including a well balanced view of TCollection/TCollectionItem usage.
--jeroen
Old answer (great iPad auto-complete bugs fixed):
Sorry for the short answer, as I am on the road only carrying a mobile device.
It looks like your mesh is a container for entities.
If so, then you should look into TCollection and TCollectionItem.
Derive your mesh from the former and your entity from the latter.
The delphi vcl source code contain many examples of these: fields/field or actions/action are good starters.