Delphi XE: Могу ли я вызывать виртуальные конструкторы с параметрами из обобщенного типа с ограниченным классическим типом, не отказываясь от хаков? - PullRequest
5 голосов
/ 06 марта 2012

Я пытаюсь построить общий предок для составных элементов управления.Первоначальная идея выглядела примерно так:

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: Невозможно создать новый экземпляр без ограничения CONSTRUCTOR в объявлении параметра типа.Однако добавление ограничения 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-недостаточно для прямого вызова виртуального конструктора для параметра типа?

Ответы [ 4 ]

6 голосов
/ 06 марта 2012

Ваш тип плохой: TControl(TControl1).Create(Self).Это говорит компилятору, что TControl1 - это экземпляр из TControl, но мы знаем, что это не экземпляр.Это ссылка на класс.Вместо этого приведите его к типу ссылки на класс:

FControl1 := TControlClass(TControl1).Create(Self);
0 голосов
/ 14 февраля 2016

Похоже, что в последней версии Delphi (Сиэтл) эта ошибка компилятора больше не выдается.У меня была та же проблема, что и у нас с приложением, но только при компиляции с DelphiXe8, а не с delphi Seattle

0 голосов
/ 11 декабря 2015

Альтернативный синтаксис:

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

Это используется в Classes.pas :: CreateComponent Delphi. Я просто не могу решить, какой вариант наименее уродлив!

0 голосов
/ 05 мая 2012

Если ваш класс использует конструктор без параметров (например, TObject), я бы предложил сделать то, что говорит компилятор:

«Добавить ограничение конструктора к объявлению параметра типа»

Это должно выглядеть примерно так:

TCompositeControl = Class (TWinControl)

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

Как бы то ни было, я не знаю, работает ли он с конструктором, которому нужен параметр.

Пожалуйста, дайте нам знать, если это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...