5

我正在尝试为复合控件构建一个通用祖先。最初的想法是这样的:

type
  TCompositeControl<TControl1: TControl; TControl2: TControl> = class(TWinControl)
  private
    FControl1,
    FControl2: TControl;
  public
    constructor Create(AOwner: TComponent); override; 
  end;

  TLabelAndEdit = TCompositeControl<TLabel, TEdit>; // simple example for illustration only

constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FControl1 := TControl1.Create(Self);
  FControl2 := TControl2.Create(Self);
end;

您可能已经知道,这将触发编译器错误 E2568: Can't create new instance without CONSTRUCTOR constraint in type parameter declaration。然而,添加constructor约束并没有帮助,因为它意味着一个无参数的构造函数。

转换模板以TControl使代码可编译:

...
FControl1 := TControl(TControl1).Create(Self);
...

...但它会在运行时导致访问冲突。

一种可能有效的技巧是通过 RTTI 调用构造函数,但我认为这是一个相当肮脏的解决方案。

另一个基本有效的技巧是使用类类型变量作为中间体:

type
  TControlClass = class of TControl;

constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent);
var
  lCtrlClass1,
  lCtrlClass2: TControlClass;
begin
  inherited Create(AOwner);
  lCtrlClass1 := TControl1;
  FControl1 := lCtrlClass1.Create(Self);
  lCtrlClass2 := TControl2;
  FControl2 := lCtrlClass2.Create(Self);
end;

有更清洁的解决方案吗?另外,有人可以向我解释为什么 classtype-constraint 不足以直接在类型参数上调用虚拟构造函数吗?

4

4 回答 4

6

你的类型转换不好:TControl(TControl1).Create(Self). 这告诉编译器这TControl1是 的一个实例TControl但我们知道它不是一个实例。这是一个类参考。将其类型转换为类引用类型:

FControl1 := TControlClass(TControl1).Create(Self);
于 2012-03-06T15:51:34.703 回答
0

似乎最新的 delphi 版本(西雅图)不再发出此编译器错误。我遇到了与应用程序相同的问题,但只有在使用 DelphiXe8 编译时才使用 delphi Seattle

于 2016-02-14T17:07:11.453 回答
0

另一种语法是

FControl1 := TControl1(TControl1.NewInstance); // get memory for object
FControl1.Create(self); // call type-specific constructor

FControl2 := TControl2(TControl2.NewInstance); // get memory for object
FControl2.Create(self); // call type-specific constructor

这用于 Delphi 的 Classes.pas::CreateComponent 我只是无法确定哪个选项最不丑!

于 2015-12-10T22:34:26.150 回答
-1

如果您的类使用不带参数的构造函数(如 TObject),我建议按照编译器的说明进行操作:

“向类型参数声明添加构造函数约束”

它应该看起来像这样:

TCompositeControl < Control1:TControl,构造函数;TControl2:TControl,构造函数 > = Class(TWinControl)

如果这样做,您应该能够对泛型类型的构造函数进行必要的调用。

但是,我不知道它是否适用于需要参数的构造函数。

请让我们知道,如果它有效。

于 2012-05-04T21:23:28.473 回答