Видимость вновь введенного конструктора - PullRequest
1 голос
/ 17 мая 2010

Я заново ввел конструктор формы в базовую форму, но если я переопределил исходный конструктор в форме-потомке, вновь введенный конструктор больше не будет виден.

type
  TfrmA = class(TForm)
  private
    FWndParent: HWnd;
  public
    constructor Create(AOwner: TComponent; const AWndParent: Hwnd); reintroduce; overload; virtual;
  end;

constructor TfrmA.Create(AOwner: TComponent; const AWndParent: Hwnd);
begin
  FWndParent := AWndParent;
  inherited Create(AOwner);
end;

type
  TfrmB = class(TfrmA)
  private
  public
  end;

type
  TfrmC = class(TfrmB)
  private
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TfrmC.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

При создании:

  frmA := TfrmA.Create(nil, 0);
  frmB := TfrmB.Create(nil, 0);
  frmC := TfrmC.Create(nil, 0); // Compiler error

Мой обходной путь - переопределить повторно введенный конструктор или объявить исходный конструктор перегруженным, но я хотел бы понять причину такого поведения.

type
  TfrmA = class(TForm)
  private
    FWndParent: HWnd;
  public
    constructor Create(AOwner: TComponent); overload; override;
    constructor Create(AOwner: TComponent; const AWndParent: Hwnd); reintroduce; overload; virtual;
  end;

type
  TfrmC = class(TfrmB)
  private
  public
    constructor Create(AOwner: TComponent; const AWndParent: Hwnd); override;
  end;

Ответы [ 2 ]

7 голосов
/ 17 мая 2010

В вашем исходном коде ваш конструктор Create скрывает оригинальный Create. Вот почему компилятор жалуется на то, что TfrmC переопределяет конструктор, которого он больше не видит.

Обычно вы получаете сообщение об этом от компилятора, но «reintroduce» подавляет это. Всякий раз, когда вам нужно «повторно ввести» для подавления сообщений компилятора, должны срабатывать сигналы тревоги, так как это указывает на то, что вы нарушаете полиморфизм. Это не значит, что вы не должны его использовать, но вы должны знать о последствиях.

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

constructor CreateWithParent(AOwner: TComponent; const AWndParent: HWnd); virtual;

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

Edit: Как я упоминал в комментариях, компилятор жалуется на tfrmC.Create (nil, 0); слишком много параметров. Кажется, что tfrmC.Create (AOwner) скрывает tfrmA.Create (AOwner, AWndParent); Думая об этом по дороге домой (пробки, кажется, имеют преимущество в конце концов), этому есть объяснение.

1) Перегрузка в tfrmA.Create не имеет прямой цели, кроме как разрешить введение других конструкторов с таким же именем. 2) Конструктор TfrmC эффективно скрывает конструктор TfrmA, повторно вводя подпись, которая была скрыта конструктором TfrmA. По сути, это не переопределение исходного конструктора, а повторное введение вновь введенного. 3) Я считаю, что компилятор должен был выдать предупреждение об этом сокрытии. Возможно, причина этого заключается в том, что директива TfrmA перегружена. Когда вы удаляете это, вы получаете сообщение об ошибке, в которой объявление TfrmC.Create отличается от предыдущего. 4) Поскольку конструктор TfrmA был скрыт TfrmC, компилятор правильно жалуется на слишком большое количество параметров в TFrmC.Create (nil, 0).

То, что описано в пункте 2), становится очевидным, когда вы добавляете сигнатуру конструктора TfrmA в TfrmC только с помощью директивы override. Затем этот конструктор немедленно перерисовывается в среде IDE. Причина: два конструктора с одинаковым именем и отсутствующей директивой перегрузки для конструктора TfrmC, который имеет только параметр AOwner.

Это также становится понятным, когда вы закомментируете второй параметр в экземпляре tfrmC и кодируете только «унаследованный»; вместо «унаследованный Create (AOwner);» в его реализации. Затем компилятор жалуется на несовместимые типы.

Последнее можно было бы решить с помощью либо «унаследованного Create (AOwner)»; (как вы сделали) или "унаследовал Create (AOwner, 0);". В то время как последний гарантировал бы возврат обратно к дереву наследования, первый мог бы сразу вернуться к TForm1.Create.

При использовании слегка измененной версии вашего кода и при условии, что TfrmC создается с одним параметром, результат "унаследованного Create (AOwner)" будет выглядеть так:

альтернативный текст http://www.bjmsoftware.com/delphistuff/overloading/InheritedCreate1Param.jpg

пока результат «унаследован Create (AOwner, 0);» было бы: альтернативный текст http://www.bjmsoftware.com/delphistuff/overloading/InheritedCreate2Params.jpg

Добавление перегрузки к конструктору TfrmC, как я предложил в комментариях, переопределяет исходный TForm1.Create и допускает два конструктора с одинаковым именем. Это можно проиллюстрировать в тестовом проекте, включив условные определения TFRMC_OVERLOAD и INSTANTIATE2. Это создает экземпляр TfrmC с TfrmC.Create (nil, 0) и приводит к:

альтернативный текст http://www.bjmsoftware.com/delphistuff/overloading/InheritedCreate2ParamsOverload.jpg

Показывает, что TfrmB.Create вызывается для TfrmC, поскольку TfrmB является первым предком с реализацией для двухпараметрического конструктора. При создании экземпляра TfrmC с помощью TfrmC.Create (nil) (отключить условное определение INSTANTIATE2) получается такой же рисунок, как первое или второе (в зависимости от определения TWOPARAMS).

5 голосов
/ 17 мая 2010

Все методы, объявленные с одним и тем же именем, должны быть перегружены. Область действия - текущее объявление класса.

Самое простое решение - снова использовать директиву overload:

type
  TfrmC = class(TfrmB)
  private
  public
    constructor Create(AOwner: TComponent); overload; override;
  end;

Причина в том, что оригинальный конструктор в TCustomForm не был объявлен перегруженным.

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