How to call a subclass constructor from a parent class?

Is there a way to call Create a subclass from the parent class? Below is this Duplicate method, in which I want the subclass constructor to be called instead, so the test below will succeed.

type IBla<T> = interface(IInvokable) ['{34E812BF-D021-422A-A051-A492F25534C4}'] function GetIntFromIface(): Integer; function Duplicate(): IBla<T>; end; TClassA<T> = class(TInterfacedObject, IBla<T>) protected function GetInt(): Integer; virtual; public function GetIntFromIface(): Integer; function Duplicate(): IBla<T>; end; TClassB = class(TClassA<Integer>, IBla<Integer>) protected function GetInt(): Integer; override; end; function TClassA<T>.Duplicate: IBla<T>; begin Exit(TClassA<T>.Create()); end; function TClassA<T>.GetInt: Integer; begin Exit(1); end; function TClassA<T>.GetIntFromIface: Integer; begin Exit(GetInt()); end; function TClassB.GetInt: Integer; begin Exit(2); end; procedure TestRandomStuff.Test123; var o1, o2: IBla<Integer>; begin o1 := TClassB.Create(); o2 := o1.Duplicate(); Assert.AreEqual(o2.GetIntFromIface, 2); end; 
+6
source share
2 answers

You can do this with RTTI:

 uses System.Rtti; .... function TClassA<T>.Duplicate: IBla<T>; var ctx: TRttiContext; typ: TRttiType; mthd: TRttiMethod; inst: TValue; begin typ := ctx.GetType(ClassInfo); mthd := typ.GetMethod('Create'); inst := mthd.Invoke((typ as TRttiInstanceType).MetaclassType, []); inst.AsObject.GetInterface(IBla<T>, Result); end; 

There is, perhaps, a cleaner way to invoke the constructor using RTTI (I know almost nothing about RTTI in Delphi), so you might think that you are reading this topic, and not considering it in a canonical way. this.

Of course, this assumes that all subclasses use the parameterless constructor defined in TObject . This can be quite limited. I would not be surprised if you have to rethink design in a more fundamental way.

If none of your subclasses implements constructors, you can make it even simpler and not use RTTI at all:

 function TClassA<T>.Duplicate: IBla<T>; begin ClassType.Create.GetInterface(IBla<T>, Result); end; 

But keep in mind that this calls the constructor defined in TObject and will not call the constructor defined in the subclass.

+4
source

It works:

 function TClassA<T>.Duplicate: IBla<T>; begin //Exit(TClassA<T>.Create()); Exit( ClassType.Create as TClassA<T> ); end; 

The subtlety is that ClassType.Create will create (in this case) TClassB, and the original creates TClassA <integer>, which the compiler sees as different from TClassB, and therefore calls TClassA <T> .GetInt, not TClassB. GetInt.

Edit

But keep in mind that this calls the constructor defined in TObject and will not call the constructor defined in the subclass. (Thanks to David X)

However, this solution also overcomes this limitation:

 interface type IBla<T> = interface(IInvokable) ['{34E812BF-D021-422A-A051-A492F25534C4}'] function GetIntFromIface(): Integer; function Duplicate(): IBla<T>; end; TClassA<T> = class(TInterfacedObject, IBla<T>) protected function GetInt(): Integer; virtual; public constructor Create; virtual; function GetIntFromIface(): Integer; function Duplicate(): IBla<T>; end; //TClassB = class(TClassA<Integer>) TClassB = class(TClassA<Integer>, IBla<Integer>) protected function GetInt(): Integer; override; public constructor Create; override; function Duplicate(): IBla<Integer>; end; procedure Test123; implementation constructor TClassA<T>.Create; begin inherited Create; end; function TClassA<T>.Duplicate: IBla<T>; begin Exit(TClassA<T>.Create()); end; function TClassA<T>.GetInt: Integer; begin Exit(1); end; function TClassA<T>.GetIntFromIface: Integer; begin Exit(GetInt()); end; constructor TClassB.Create; begin inherited Create; end; function TClassB.Duplicate: IBla<Integer>; begin Result := TClassB.Create; end; function TClassB.GetInt: Integer; begin Exit(2); end; procedure Test123; var o1, o2: IBla<Integer>; begin o1 := TClassB.Create(); o2 := o1.Duplicate(); Assert( o2.GetIntFromIface = 2); end; 
0
source

Source: https://habr.com/ru/post/1012887/


All Articles