Dmitry Onoshko 0 Posted October 14 What I would like to achieve is along the lines of: type TAncestor = class FData: TArray<???>; // ... // A lot of methods that load, export, change FData // in a way common to all the descendants (mostly Length // and SetLength are used) // // Differences in managing FData are extracted into // protected virtual methods // ... end; TAncestorClass = class of TAncestor; TDescendant1 = class(TAncestor) type TItem = ... // Some type // ... // Virtual methods that do descendant-specific things // are overriden here // ... end; TDescendant2 = class(TAncestor) type TItem = ... // Another type // ... // Virtual methods that do descendant-specific things // are overriden here // ... end; ... The TItem-specific code is all in descendants, TAncestor just implements general management of how and when to resize FData and provides boilerplate code for loading, exporting and performing container-level changes on the data thatwould otherwise be duplicated in every descendant. This could probably be achieved with generics (descending from TAncestor<T> with particular T for each descendant), but this approach fails to support metaclasses and nested types. Am I missing something or is this not possible? Share this post Link to post
Remy Lebeau 1392 Posted October 14 1 hour ago, Dmitry Onoshko said: This could probably be achieved with generics (descending from TAncestor<T> with particular T for each descendant), but this approach fails to support metaclasses and nested types. Am I missing something or is this not possible? Why not simply define a base class for the items to derive from? Then you can have an array of base items, and the derived classes can cast the items as needed. type TItemBase = class end; TAncestor = class FData: TArray<TItemBase>; // ... end; TAncestorClass = class of TAncestor; TDescendant1 = class(TAncestor) type TItem = class(TItemBase) //... end; // ... // cast FData elements to TItem as needed... end; TDescendant2 = class(TAncestor) type TItem = class(TItemBase) //... end; // ... // cast FData elements to TItem as needed... end; ... Share this post Link to post
Dmitry Onoshko 0 Posted October 14 3 minutes ago, Remy Lebeau said: Why not simply define a base class for the items to derive from? Then you can have an array of base items, and the derived classes can cast the items as needed. This would turn the whole “dataset” into an array of pointers to a lot of dynamically-allocated pieces. Not quite cache-friendly, the overhead of allocations, etc. The reason to use the dynamic array in the first place was to store data in a single block of memory having all the benefits of good old PODs. Share this post Link to post
Dmitry Onoshko 0 Posted October 14 Meanwhile one thing came to my mind. Along the lines of: type TAncestor = class // All the stuff goes here, but no FData definition // Pieces of code that use FData directly are // virtual abstract methods here end; TAncestorClass = class of TAncestor; TAncestor<T> = class(TAncestor) FData: TArray<T>; // Override FData-related methods common to all classes // in the hierarchy here end; TDescendant1Item = ... TDescendant1 = class(TAncestor<TDescendant1Item>) // ... end; TDescendant2Item = ... TDescendant2 = class(TAncestor<TDescendant2Item>) // ... end; Lets remove duplicate code from descendants but adds a lot of TXxxxItem type identifiers to the global namespace. Having a way to hide them would be great as the types are for particular class’ internal implementation only. Share this post Link to post