Recent

Author Topic: Inheritance of Classes that Inherit from Object Lists  (Read 479 times)

CMELIGM

  • New Member
  • *
  • Posts: 11
Inheritance of Classes that Inherit from Object Lists
« on: June 20, 2025, 08:54:23 am »
Hello,

i have the following Code strukture:

Code: Pascal  [Select][+][-]
  1.   { TBaseItem }
  2.   TBaseItem = class
  3.   private
  4.     fID: string;
  5.     fPrice: double;
  6.     fName: string;
  7.     fOnChange: TNotifyEvent;
  8.     function GetDisplayName: string;
  9.     procedure SetName(AValue: string);
  10.     procedure SetPreis(AValue: double);
  11.   protected
  12.     property OnChange: TNotifyEvent read fOnChange write fOnChange;
  13.     procedure Changed;
  14.   public
  15.     property ID: string read fID;
  16.     property Price: double read fPrice write SetPreis;
  17.     property Name: string read fName write SetName;
  18.     property DisplayName: string read GetDisplayName;
  19.     constructor Create; virtual;
  20.   end;
  21.  
  22.   TItemList = specialize TFPGObjectList<TBaseItem>;
  23.   { TBaseList }
  24.   TBaseList = class(TItemList)
  25.   private
  26.     fUpdateCount: integer;
  27.     fOnChange: TNotifyEvent;
  28.     fTableName: string;
  29.     fQuery: TSQLQuery;
  30.     fLoadInUseOnly: boolean;
  31.   protected
  32.     procedure Changed;
  33.   public
  34.     property TableName: string read fTableName write fTableName;
  35.     property LoadInUseOnly: boolean read fLoadInUseOnly write fLoadInUseOnly;
  36.     property OnChange: TNotifyEvent read fOnChange write fOnChange;
  37.     constructor Create(cFreeObjects: Boolean=True);
  38.     destructor Destroy; override;
  39.     function Add(const Item: TBaseItem): integer;
  40.     function Remove(const Item: TBaseItem): integer;
  41.     function Load: integer; virtual; abstract;
  42.     function Save: integer; virtual; abstract;
  43.     procedure BeginUpdate;
  44.     procedure EndUpdate;
  45.   end;
  46.  
  47.   { TFilterItem }
  48.   TFilterItem = class(TBaseItem)
  49.   private
  50.     fWidth: double;
  51.     fHeight: double;
  52.     fDepth: double;
  53.     fDBPosition: integer;
  54.   public
  55.     property Width: double read fWidth write fWidth;
  56.     property Height: double read fHeight write fHeight;
  57.     property Depth: double read fDepth write fDepth;
  58.     constructor Create; override;
  59.   end;
  60.  
  61.   { TFilterList }
  62.   TFilterList = class(TBaseList)
  63.   private
  64.     function GetI(Index: Integer): TFilterItem;
  65.     procedure PutI(Index: Integer; const Item: TFilterItem);
  66.   public
  67.     property Items[Index: Integer]: TFilterItem read GetI write PutI; default;
  68.     constructor Create(cFreeObjects: Boolean=True);
  69.     function Add(const Item: TFilterItem): integer; virtual;
  70.     function Remove(const Item: TFilterItem): integer; virtual;
  71.     function Save: integer; override;
  72.     function Load: integer; override;
  73.   end;    
  74.  

the FilterList will inherit from the BaseList. The baselist will inherit from

Code: Pascal  [Select][+][-]
  1. TItemList = specialize TFPGObjectList<TBaseItem>;
  2.  

FilterList should inherit from this:

Code: Pascal  [Select][+][-]
  1. TFilterList = specialize TFPGObjectList<TFilterItem >;
  2.  

but i want it to inherit from TBaseList. How do i specialize the Child List to "TFilterItem" instea of "TBaseItem". Is this the wrong approach for this ?
it works whe i write the "Items property myself" like i did in the example. i am not sure if that was the correct way of doing this though.
i am clearly missing something her, thanks in advance for any helpful hints.
« Last Edit: June 20, 2025, 08:56:00 am by CMELIGM »

gues1

  • Jr. Member
  • **
  • Posts: 84
Re: Inheritance of Classes that Inherit from Object Lists
« Reply #1 on: June 20, 2025, 09:54:53 am »
May be I'm totally wrong, but I think you should work with Interfaces: the two TFilterItem and TFilterList should be interfaces instead of Class.

MultiInheritance is not permitted in Pascal, but you can use Interfaces to make "common way" to access "data"

Look at: https://wiki.freepascal.org/Understanding_Interfaces

egsuh

  • Hero Member
  • *****
  • Posts: 1623
Re: Inheritance of Classes that Inherit from Object Lists
« Reply #2 on: June 20, 2025, 10:21:19 am »
This is really interesting. Isn't there no way to define <T> within generic class definitions?

Warfley

  • Hero Member
  • *****
  • Posts: 1930
Re: Inheritance of Classes that Inherit from Object Lists
« Reply #3 on: June 20, 2025, 10:55:40 am »
While what you describe seems to make sense for generic containers, generics are much more than just containers. Unlike for example Java where generics are implemented via type erasure, fpcs generics are templates, and here inheritance may not make sense.

Take for example:
Code: Pascal  [Select][+][-]
  1. type
  2.   generic TMyAllocator<T: TObject> = class
  3.   public
  4.     function Alloc: Pointer;
  5.   end;
  6.  
  7. function TMyAllocator.Alloc: Pointer;
  8. begin
  9.   Result:=GetMem(T.InstanceSize);
  10. end;

TMyAllocator<TObject> and TMyAllocator<TStringList> do something completely differently (in allocating different chunks of memory) and just because TStringList inferits from TObject does not mean that the allocators are related

CMELIGM

  • New Member
  • *
  • Posts: 11
Re: Inheritance of Classes that Inherit from Object Lists
« Reply #4 on: June 23, 2025, 07:45:27 am »
Interfaces do not seem to be the ideal choice for me. I would still need to rewrite everything my BaseClass has for every other class right ? As far as i understood the interface just tells the class what it needs to implement ?

And for the generic Lists. I need to read a bit more about it since i never used it.

Could i also write a Helper class for the Objectlist ? So i could skip the Inheritance of the base list. Is this a bad idea ?.

Code: Pascal  [Select][+][-]
  1.   TFPGObjectListHelper = class helper for TFPGObjectList
  2.   private
  3.     fUpdateCount: integer;
  4.     fOnChange: TNotifyEvent;
  5.  
  6.     //etc ...
  7.   end;
  8.  
  9.   { TBaseItem }
  10.   TBaseItem = class
  11.   private
  12.     fID: string;
  13.     fPrice: double;
  14.     fName: string;
  15.     fOnChange: TNotifyEvent;
  16.     function GetDisplayName: string;
  17.     procedure SetName(AValue: string);
  18.     procedure SetPreis(AValue: double);
  19.   protected
  20.     property OnChange: TNotifyEvent read fOnChange write fOnChange;
  21.     procedure Changed;
  22.   public
  23.     property ID: string read fID;
  24.     property Price: double read fPrice write SetPreis;
  25.     property Name: string read fName write SetName;
  26.     property DisplayName: string read GetDisplayName;
  27.     constructor Create; virtual;
  28.   end;
  29.  
  30.   TItemList = specialize TFPGObjectList<TBaseItem>;
  31.  
  32.   { TFilterItem }
  33.   TFilterItem = class(TBaseItem)
  34.   private
  35.     fWidth: double;
  36.     fHeight: double;
  37.     fDepth: double;
  38.     fDBPosition: integer;
  39.   public
  40.     property Width: double read fWidth write fWidth;
  41.     property Height: double read fHeight write fHeight;
  42.     property Depth: double read fDepth write fDepth;
  43.     constructor Create; override;
  44.   end;
  45.  
  46.    TFilterItemList = specialize TFPGObjectList<TFilterItem>;
  47.   { TFilterList }
  48.   TFilterList = class(TFilterItemList )
  49.   private
  50.     function GetI(Index: Integer): TFilterItem;
  51.     procedure PutI(Index: Integer; const Item: TFilterItem);
  52.   public
  53.     property Items[Index: Integer]: TFilterItem read GetI write PutI; default;
  54.     constructor Create(cFreeObjects: Boolean=True);
  55.     function Add(const Item: TFilterItem): integer; virtual;
  56.     function Remove(const Item: TFilterItem): integer; virtual;
  57.     function Save: integer; override;
  58.     function Load: integer; override;
  59.   end;    
  60.  
  61.  

Edit: Just checked Collections, which might be the way to go for me
« Last Edit: June 23, 2025, 08:12:55 am by CMELIGM »

Thaddy

  • Hero Member
  • *****
  • Posts: 17451
  • Ceterum censeo Trumpum esse delendum (Tnx Charlie)
Re: Inheritance of Classes that Inherit from Object Lists
« Reply #5 on: June 23, 2025, 09:31:25 am »
Interfaces do not seem to be the ideal choice for me. I would still need to rewrite everything my BaseClass has for every other class right ?
No, everything from your base class will be inherited.
Just methods you want to change in child classes need to be marked with virtual and subs overload:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. type
  3.  THello= class
  4.  public
  5.     procedure Doit;virtual;
  6.  end;
  7.  
  8.  TWorld = class(THello)
  9.  public
  10.     procedure Doit;override;
  11.  end;
  12.  
  13. THelloWorld = class(TWorld)
  14. public
  15.   procedure Doit;override;
  16. end;
  17.  
  18.  procedure THello.Doit;
  19.  begin
  20.    write('Hello');
  21.  end;
  22.  
  23.  procedure TWorld.Doit;
  24.  begin
  25.    inherited;
  26.    writeln(', world');
  27.  end;
  28.  
  29.  procedure THelloWorld.Doit;
  30.  begin
  31.     inherited;
  32.    writeln('Goodbye');
  33.  end;
  34.  
  35. var
  36.    Hello,World,HelloWorld:THello;
  37. begin
  38.    Hello := THello.Create;
  39.    World := TWorld.Create;
  40.    HelloWorld := THelloWorld.Create;
  41.    Hello.Doit;
  42.    writeln;
  43.    World.DoIt;
  44.    HelloWorld.DoIt;
  45.    HelloWorld.Free;
  46.    World.Free;
  47.    Hello.Free;
  48. end.
That is a common misconception.
Override can of course also be used to change the behavior of a virtual method completely if you leave out the inherited calls.
Again, you do not need to repeat all implementation, just what needs to change.

BTW: parameterless constructors can not be virtual without a trick: they need to be virtual;reintroduce; to avoid warnings and it is advised to call inherited in that virtual one.

 
« Last Edit: June 23, 2025, 09:51:11 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

 

TinyPortal © 2005-2018