Работа С Переменными Класса-Потомка В Базовом Классе

Почему это необходимо? С этой необходимостью я столкнулся, например, при сериализации классов.

Было желание весь рутинный код и информацию о классах-потомках переместить в базовый класс.

Ну лень писать одно и то же для каждого дочернего класса.

Поэтому я начал думать, может быть, я мог бы добавить сюда дженерики.

А так, нужные переменные класса можно завернуть в запись, динамически выделить для них память и затем использовать через указатель.

Этот указатель будет храниться в переменной класса промежуточного универсального класса.

Этот обобщенный класс станет новым уникальным базовым классом для различных последующих классов.

Чтобы получить доступ к таким данным из конкретного экземпляра класса, вы можете добавить поле указателя, которое будет инициализировано в конструкторе универсального класса.

А чтобы передать этот указатель методам базового класса, используйте дополнительный параметр.

Подмена значения этого параметра, возможно, вместо скрытого ClassSelf, будет осуществляться в перегруженных методах промежуточного обобщенного класса.

Вариант реализации базовых и универсальных классов:

  
   

unit MyStore; interface uses System.Generics.Collections; type TDataBase = class abstract protected type TDataType = class of TDataBase; TDataList = TList<TDataBase>; TDataInfo = array of Integer; PClassVar = ^TClassVar; TClassVar = record cType :TDataType; cObjs :TDataList; cInfo :TDataInfo; end; protected fVar :PClassVar; class function Init(var cVar :PClassVar):Pointer; overload; class procedure Done(var cVar :PClassVar); overload; static; class procedure AddFild( cVar :PClassVar; var Fild); overload; static; public Tag :Integer; procedure Save; constructor Create; virtual; destructor Destroy; override; end; TDataProx<T:class> = class(TDataBase) protected class var cVar :TDataBase.PClassVar; class function Init:T; overload; inline; class procedure Done; overload; inline; class procedure AddFild(var Fild); overload; inline; public constructor Create; overload; override; class function Objs:TList<T>; inline; end; implementation { TDataBase } class procedure TDataBase.AddFild(cVar: PClassVar; var Fild); // static; begin with cVar^ do begin SetLength(cInfo,Length(cInfo)+1); cInfo[Length(cInfo)-1]:=Integer(PByte(@Fild) - PByte(@cType)); end; end; procedure TDataBase.Save; begin with fVar^ do begin end; end; constructor TDataBase.Create; begin with fVar^ do cObjs.Add(Self); end; destructor TDataBase.Destroy; begin with fVar^ do cObjs.Extract(Self); inherited; end; class procedure TDataBase.Done(var cVar: PClassVar); // static; var Obj :TDataBase; begin with cVar^ do begin for Obj in cObjs do begin Obj.Save; Obj.Free; end; cObjs.Free; Finalize(cInfo); end; Dispose(cVar); end; class function TDataBase.Init(var cVar: PClassVar):Pointer; // uses ClassSelf begin New(cVar); with cVar^ do begin cType:=Self; cObjs:=TDataList.Create; Initialize(cInfo); Result:=@cType; // synthetic Object :) end; AddFild(cVar,TDataBase(Result).

Tag); end; { TDataProx<T> } class procedure TDataProx<T>.

AddFild(var Fild); // inline; begin AddFild(cVar, Fild); end; constructor TDataProx<T>.

Create; begin fVar := cVar; // ! inherited; // ! after fVar := cVar; end; class procedure TDataProx<T>.

Done; // inline; begin Done(cVar); end; class function TDataProx<T>.

Init:T; // inline; begin Result:=Init(cVar); end; class function TDataProx<T>.

Objs: TList<T>; // inline begin Result:=TList<T>(cVar.cObjs); end; end.

Пример использования:

unit MyData; interface uses MyStore; type TDataA = class(TDataProx<TDataA>) Data :Integer; Note: string; class constructor Init; class destructor Done; class procedure Work; end; TDataB = class(TDataProx<TDataB>) Data :Double; Memo :array of string; class constructor Init; class destructor Done; end; implementation { DataA } class destructor TDataA.Done; begin Done; end; class constructor TDataA.Init; begin with Init do begin AddFild(Data); AddFild(Note); end; end; class procedure TDataA.Work; var Obj :TDataA; begin for Obj in Objs do Inc(Obj.Data,Obj.Tag); end; { DataB } class destructor TDataB.Done; begin Done; end; class constructor TDataB.Init; begin with Init do begin AddFild(Data); AddFild(Memo); end; end; end.

Теги: #delphi #дженерики #ООП #delphi
Вместе с данным постом часто просматривают: