继承泛型参数在Delphi XE中不起作用

den*_*nis 4 delphi generics inheritance delphi-xe

我一直试图通过覆盖在该基类中定义的虚方法来扩展从同一基类继承的一堆库类.修改总是相同的,所以我决定创建一个由库类类参数化的泛型类,而不是创建库类的N​​个后继类,它继承自参数指定的类,并覆盖基类的方法.问题是下面的代码没有编译,编译器不允许从T继承:

program Project1;

type
  LibraryBaseClass = class
    procedure foo; virtual;
  end;

  LibraryClassA = class(LibraryBaseClass)
  end;

  LibraryClassB = class(LibraryBaseClass)
  end;

  LibraryClassC = class(LibraryBaseClass)
  end;

  LibraryClassD = class(LibraryBaseClass)
  end;

  MyClass<T:LibraryBaseClass> = class(T) //Project1.dpr(20) Error: E2021 Class type required
    procedure foo; override;
  end;

procedure LibraryBaseClass.foo; 
begin
end;

procedure MyClass<T>.foo; 
begin
end;

begin
  MyClass<LibraryClassA>.Create.foo;
  MyClass<LibraryClassB>.Create.foo;
  MyClass<LibraryClassC>.Create.foo;
  MyClass<LibraryClassD>.Create.foo;
end.
Run Code Online (Sandbox Code Playgroud)

任何想法如何使这项工作?也许有一种方法可以欺骗编译器接受等价的东西,例如,从Dictionary<T,T>编译继承而没有问题.

或者,如果你和我有同样的目标,你会怎么做?请记住,在实际情况中,我需要覆盖多个方法并添加一些数据成员.

谢谢

小智 9

正如您已经被告知的那样,这对C++模板有效,而不是C#或Delphi泛型.模板和泛型之间的根本区别在于,从概念上讲,每个模板实例化都是完全独立编译的类型.对于所有可能的类型,泛型编译一次.从类型参数派生时,这是不可能的,因为你可以获得诸如的结构

type
  LibraryBaseClass = class
    procedure foo; virtual;
  end;

  LibraryClassA = class(LibraryBaseClass)
    procedure foo; reintroduce; virtual;
  end;

  LibraryClassB = class(LibraryBaseClass)
  end;

  MyClass<T:LibraryBaseClass> = class(T)
    procedure foo; override; // overrides LibraryClass.foo or LibraryClassA.foo ?
  end;
Run Code Online (Sandbox Code Playgroud)

然而,这可以在C++中工作,因为在C++中MyClass<LibraryClassA>并且MyClass<LibraryClassB>完全分离,并且在实例化时MyClass<LibraryClassA>,foo在找到LibraryClassA基类方法之前查找并找到它.

或者,如果你和我有同样的目标,你会怎么做?请记住,在实际情况中,我需要覆盖多个方法并添加一些数据成员.

这是有可能创造类型在运行,但几乎可以肯定的非常糟糕的主意.我不得不一次使用它,并希望避免它.它涉及读取VMT,创建它的副本,在LibraryBaseClass.foo某处存储原始方法指针的副本,修改VMT以指向自定义方法,以及从该重写函数调用原始存储的方法指针.当然没有内置的语言支持,并且无法从代码中引用派生类型.

我曾经在C#中有过这样的需求,但是在那种情况下我很幸运,只有四个可能的基类.我最终手动创建了四个单独的派生类,实现了四次方法,并使用查找结构(Dictionary<,>)将正确的基类映射到正确的派生类.

请注意,对于不适用你的问题的特定情况下的伎俩,但可以帮助其他读者:如果你的派生类都必须实现相同的接口,无需新的数据成员和功能覆盖,你能避免写作多次执行:

type
  IMySpecialInterface = interface
    procedure ShowName;
  end;

  TMySpecialInterfaceHelper = class helper for TComponent
    procedure ShowName;
  end;

procedure TMySpecialInterfaceHelper.ShowName;
begin
  ShowMessage(Name);
end;

type
  TLabelWithShowName = class(TLabel, IMySpecialInterface);
  TButtonWithShowName = class(TButton, IMySpecialInterface);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,类助手方法实现将是接口方法的有效实现.