如何从父 class 调用 subclass 构造函数?
How can the subclass constructor be called from the parent class?
有没有办法从父 class 调用子 class 的创建?下面是这个 Duplicate 方法,我希望在其中调用 subclass 的构造函数,以便底部的测试成功。
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;
您可以使用 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;
很可能有一种使用 RTTI 调用构造函数的更简洁的方法(我对 Delphi 中的 RTTI 几乎一无所知),因此您最好阅读该主题而不是将上述内容视为是执行此操作的规范方法。
当然,这是假设所有子类都使用TObject
中定义的无参数构造函数。这可能相当有限。如果您发现自己不得不以更基本的方式重新考虑设计,我不会感到惊讶。
如果您的 none 个子类实现了构造函数,那么您可以使其更简单,并且根本不使用 RTTI:
function TClassA<T>.Duplicate: IBla<T>;
begin
ClassType.Create.GetInterface(IBla<T>, Result);
end;
但请注意,这会调用TObject
中定义的构造函数,而不会调用子类中定义的任何构造函数。
这似乎有效:
function TClassA<T>.Duplicate: IBla<T>;
begin
//Exit(TClassA<T>.Create());
Exit( ClassType.Create as TClassA<T> );
end;
微妙之处在于 ClassType.Create 将创建(在本例中)一个 TClassB,而原始创建一个 TClassA< integer >,编译器认为它与 TClassB 不同,因此调用 TClassA< T >.GetInt而不是 TClassB.GetInt.
编辑
但请注意,这会调用TObject 中定义的构造函数,而不会调用子类中定义的任何构造函数。 (感谢 David H)
但是,这里也有克服该限制的解决方案:
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;
有没有办法从父 class 调用子 class 的创建?下面是这个 Duplicate 方法,我希望在其中调用 subclass 的构造函数,以便底部的测试成功。
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;
您可以使用 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;
很可能有一种使用 RTTI 调用构造函数的更简洁的方法(我对 Delphi 中的 RTTI 几乎一无所知),因此您最好阅读该主题而不是将上述内容视为是执行此操作的规范方法。
当然,这是假设所有子类都使用TObject
中定义的无参数构造函数。这可能相当有限。如果您发现自己不得不以更基本的方式重新考虑设计,我不会感到惊讶。
如果您的 none 个子类实现了构造函数,那么您可以使其更简单,并且根本不使用 RTTI:
function TClassA<T>.Duplicate: IBla<T>;
begin
ClassType.Create.GetInterface(IBla<T>, Result);
end;
但请注意,这会调用TObject
中定义的构造函数,而不会调用子类中定义的任何构造函数。
这似乎有效:
function TClassA<T>.Duplicate: IBla<T>;
begin
//Exit(TClassA<T>.Create());
Exit( ClassType.Create as TClassA<T> );
end;
微妙之处在于 ClassType.Create 将创建(在本例中)一个 TClassB,而原始创建一个 TClassA< integer >,编译器认为它与 TClassB 不同,因此调用 TClassA< T >.GetInt而不是 TClassB.GetInt.
编辑
但请注意,这会调用TObject 中定义的构造函数,而不会调用子类中定义的任何构造函数。 (感谢 David H)
但是,这里也有克服该限制的解决方案:
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;