Delphi: Когда вновь появляются шкуры предков и когда они показывают их?

сегодня Недавно на Stackoverflow я узнал, что:

реинтродукция используется дляскрывать конструкторы предковреинтродукция используется дляшоу конструкторы предков

Я пытался разобраться во всем этом, так что вот еще один, очень специфический вопрос,поддерживая мой главный вопрос, касающийся конструкторов.

Обновить: заменил весь вопрос:

TComputer = class(TObject)
public
   constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

При создании TCellPhone доступны 3 конструктора:

Кубок: целое числоКубок: целое число; Чайник: строка[Чайник: Строка = '']

Вопрос: почемуconstructor(Teapot: string='') не быть скрытым?

Теперь я добавил третьего потомка:

TComputer = class(TObject)
public
   constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

TiPhone = class(TCellPhone)
public
   constructor Create(Cup: Integer); override;
end;

При строительствеTiPhone четыре Конструкторы доступны:

Кубок: целое числоКубок: целое числоКубок: целое число; Чайник: строка[Чайник: строка = '']

Почему тамчетыре Конструкторы? я переиграл одну из существующих трех.Редактировать: Это может быть ошибкой в ​​проницательности кода, она показывает мне четыре - но как я могу тогда звонить, когда два одинаковы.

Используя оригинальный код снова:

TComputer = class(TObject)
public
   constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

уже известно, чтоTCellPhone имеет три конструктора:

Кубок: целое числоКубок: целое число; Чайник: строка[Чайник: Строка = '']

Как я могу изменить декларациюTCellPhone скрыть конструктор предка? например чтобы:

TNokia = class(TCellPhone)
end;

будет иметь только два конструктора:

Кубок: целое числоКубок: целое число; Чайник: строка

Теперь для случая, когдаreintroduce используется, чтобы скрыть не виртуального предка. В предыдущем случаеTiPhone имеет четыре конструктора (в идеале было бы только два - сTComputer как-то скрывает своего предка). Но даже если я не могу исправитьTComputer, я могу изменитьTiPhone иметь только один:

TComputer = class(TObject)
public
    constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
    constructor Create(Cup: Integer); overload; virtual;
    constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

TiPhone = class(TCellPhone)
public
    constructor Create(Cup: Integer); reintroduce;
end;

СейчасTiPhone имеет только один конструктор:

Кубок: целое число

Повторное введение обычно используется только для подавления предупреждения о сокрытиивиртуальный предки. В этом случае:

Create(Teapot: string = '')

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

Носейчас, если я добавлю еще один перегруженTiPhone:

TiPhone = class(TCellPhone)
public
   constructor Create(Cup: Integer); reintroduce; overload;
   constructor Create(Handle: String); overload;
end;

Затем внезапно возвращаются (ранее скрытые) предки:

TiPhone.Create (7);TiPhone.Create ( 'розовый');TiPhone.Create (7, «розовый»);TiPhone.Create ();

Как вы видите, я изо всех сил пытаюсь понять логику

когда что-то скрытокак спрятать что-токогда что-то показанокак показать что-то
 Rob Kennedy06 окт. 2010 г., 23:43
Вы действительно говорите, что можете скомпилироватьobj := TCellPhone.Create('foo')? Я нахожу это удивительным.
 Andreas Rejbrand06 окт. 2010 г., 23:34
@Ian: Вы действительно задаете много вопросов сегодня! Ницца!
 Ian Boyd07 окт. 2010 г., 16:20
@Rob Да, кажется, что очень незначительные различия кардинально меняют ответ и понимание этой темы: /
 Rob Kennedy07 окт. 2010 г., 15:50
Нет, Ян, я просто хотел убедиться, что я правильно интерпретировал то, что вы сказали, потому что код здесь не идентичен [@ Muhammad's example] [1] - базовый метод не виртуален, и в его потомке есть несколько методов ни чего не используюreintroduce.
 Ian Boyd07 окт. 2010 г., 15:31
@ Роб Кеннеди, я могу изменить вопрос со скриншотом, если хотите?
 Muhammad Alkarouri07 окт. 2010 г., 00:07
Я, конечно, запустить полный пример, используя эти определения. К счастью, у нас уже есть ответ ниже.
 Ian Boyd07 окт. 2010 г., 15:30
@ Андреас Рейбранд, я знаю, я знаю. Но когда я задаю вопросы "большой картины", я не получаю подробных ответов. Поэтому я должен задать крошечные вопросы и собрать их вместе. Я также нахожусь в своем уме, чтобы понять смысл всего этого. Даже Роб, два комментария выше, не может поверить, что код, который я представил, работает. По крайней мере, я не одинок в своем замешательстве.

Ответы на вопрос(4)

Ну, кажется, вы не можете скрыть метод / конструктор в классе, где вы также перегружаете его. Я пришел с этим крошечным «хаком», чтобы скрыть конструктор от TComputer.

  TComputer = class(TObject)
  public
      constructor Create(Teapot: string='');
  end;

  THackComputer = class(TComputer)
  public
    constructor Create(Cup : Integer);virtual;
  end;

  TCellPhone = class(THackComputer)
  public
      constructor Create(Cup: Integer); overload; override;
      constructor Create(Cup: Integer; Teapot: string); overload; virtual;
  end;

  TiPhone = class(TCellPhone)
  public
    constructor Create(Cup: Integer); reintroduce; virtual;
  end;

В этом примере TiPhone будет иметь только 1 конструктор. Это действительно нарушает полиморфизм (цена, которую нужно заплатить, чтобы скрыть 2-й конструктор от TCellPhone). Я хотел бы знать, нашел ли кто-нибудь способ сделать это, не нарушая полиморфизм.

Кроме того, обратите внимание, что это не потому, что понимание кода показывает вам 4 «конструктора», что действительно есть 4 доступных. Я отметил, что для каждого «переопределения» конструктора в описании кода должен быть указан 1 конструктор. Но в этой ситуации будет вызван только конструктор-потомок.

Этот пример будет жаловаться, что 2-й конструктор TCellPhone скрывает один из THackComputer, но я думаю, что это ложный положительный результат, так как тот из THackComputer переопределяется в TCellPhone. (Я полагаю, ошибка в угловом случае, поскольку это не очень распространенная структура кода)

 Ken Bourassa08 окт. 2010 г., 15:05
Ну, как я уже сказал, это может быть просто ошибкой. Некоторая структура кода обманывает компилятор тем, что время от времени выдает предупреждения «Ложные срабатывания».
 Ian Boyd07 окт. 2010 г., 23:00
Это очень изящный трюк. я получаю ту же проблему, что и вы (жалуется, что другой конструктор вTCellPhone скрывает тот отTHackComputer). Объяснение того, почему он жалуется, заслуживает того, чтобы его задать - в пятом вопросе о конструкторах в Delphi. Причина в том, чтоя не понимаю, почему это жалуетсяи это всегда возможность учиться.
Решение Вопроса

Вы не используетеreintroduce скрыть метод класса предка. Это можно сделать, просто объявив метод с тем же именем, что и в классе предка, без переопределения или перегрузки. Ты используешьreintroduce подавитьпредупреждение тот Delphi возникает, когда метод класса предка (тот, который скрыт) является виртуальным.

Если метод потомкаПереопределение предка, значит, он не прячется. Вызовы метода предка вместо этого направляются к потомку.

Если метод потомкаперегрузки предка, то он тоже не прячется. Оба доступны для вызова.

 Rob Kennedy07 окт. 2010 г., 15:51
Боюсь, что не могу, @Ian. Это потребует от меня экспериментов, и у меня нет компилятора Delphi для этого. Кто-то еще должен будет перечислить все различные способы, которыми эти директивы могут использоваться вместе, и какие эффекты имеют (или не имеют).
 Ian Boyd07 окт. 2010 г., 16:37
я расширю вопрос гдеreintroduce скрывает не-виртуальный метод предка (или, возможно, это побочный эффект от подавления предупреждения)
 Ian Boyd07 окт. 2010 г., 15:37
В отношении того, что сказал Мухаммед, вы можете расширить свой ответ, Роб, чтобы объяснить, что происходит в этом случае (случай, когда добавлениеreintroduce является используется, чтобы скрыть метод класса предка)?
 Muhammad Alkarouri07 окт. 2010 г., 00:25
Существует особый случай перегрузки виртуального метода. Вы получаете использовать в сочетанииreintroduce; overload;, Это, кажется, не вписывается в ваше объяснение, как голыйoverload действительно производит предупреждение.

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

редактировать: Я бы снял свое утверждение"ты ничего не прячешь", Я думаю, что я не совсем понимаю смысл скрываться здесь. Я спросилquesiton на этом.

Обновить:
На основеответ Я хотел бы перефразировать мой ответ:TComputer.Constructor не объявлен виртуальным, вы уже скрыли этот метод от классов-потомков. Так,TCellPhone конструкторы не могут скрыть то, что вообще не было видно, следовательно, нет предупреждения компилятора.

 Sertac Akyuz07 окт. 2010 г., 17:21
@ Ян - Это скрыто, потому что это не виртуально. Или еще раз: если он не виртуальный, он скрыт, поскольку вы не можете его переопределить. Ну, по крайней мере, так я это понимаю ..
 Sertac Akyuz07 окт. 2010 г., 18:23
@ Ян - Все действительно сводится к тому, чтоскрытый средства. Если это означает «вы не сможете получить доступ к конструктору TComputer», вы абсолютно правы. Однако, если это означает, что «вы не сможете переопределить конструктор TComputer от потомков TCellPhone», я должен быть прав. Если это означает что-то еще, .. кто знает!
 Ian Boyd07 окт. 2010 г., 17:13
@Sertac Akyuz Вы не можете переопределитьTComputer.Constructor потому что это не виртуально - не потому что это «скрыто».
 Rob Kennedy07 окт. 2010 г., 15:54
Но Сертак, что Ян говорит, чтоTComputer.Create не скрыто в этом случае. Он может позвонитьTCellPhone.Create('foo')и код компилируется и запускается, создаваяTCellPhone объект. Он предложил сделать снимок экрана, чтобы доказать это.
 Ian Boyd07 окт. 2010 г., 17:45
@Sertac Но это не скрытоа также это не виртуально.
 Muhammad Alkarouri07 окт. 2010 г., 00:05
Это правильный ответ. В частности, конструкторTComputer должен быть виртуальным, чтобы вызвать предупреждения.
 Sertac Akyuz07 окт. 2010 г., 16:18
@Rob - я спросилвопрос о том, что имел в виду компиляторпрячется, Дело не в том, чтобы вообще не звонить, а в том, что вы не сможете переопределитьTComputer.Constructor у потомковTCellPhone, Посмотри пожалуйстаОтвет Кена и комментарий Барри.

Я хотел поместить это как комментарий к ответу Роба Кеннеди, но так как я не могу, здесь я иду ..

Все время нет никаких предупреждений о сокрытии конструкторов предков.

Просто потому, что ты этого не делаешь.

Если я прячу предка, почему нет предупреждения? я не представляю

Опять же, просто потому, что вы ничего не скрываете.

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

Почему реинтродукция может быть использована, чтобы скрыть предка?

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

Я хотел бы высказать свое мнение о том, как скрыться, но я согласен с Sertac, сначала я должен знать, каково ваше определение сокрытия в этом случае.

Изменить: Я только что прочитал сообщения, которые вы упомянули, я думаю, что вы неправильно поняли концепции. Вот мое краткое объяснение.

повторное введение используется, чтобы скрыть конструкторы предков

Ответ этого поста не указывает на это. Тот, который действительно скрывает конструктор предка, это НОВЫЙ КОНСТРУКТОР потомка с тем же параметром, что и у предка. Ключевое слово reintroduce просто подавляет предупреждение компилятора.

повторное введение используется, чтобы показать конструкторы предков

В ответе на этот пост ключевое слово OVERLOAD делает конструктор предка по-прежнему доступным.

ДОПОЛНЕНИЕ в ответ на вопрос Яна в его комментарии ниже:

Первым шагом к решению вашей путаницы является выявление реальных проблем. Если мы внимательно изучим ваши сообщения, станет очевидно, что вы на самом деле хотели решить две проблемы за один шаг. Две проблемы:

Чтобы скрыть конструктор предка с определенным именемИметь несколько конструкторов с одинаковыми именами в потомке.

Хотя они могут показаться простыми проблемами, но тщательный осмотр сразу же поразит вашу голову, что их натуры в точности противоположны друг другу. Задача 1 хочет скрыть метод / конструктор, в то время как задача 2 хочет показать не только один, но несколько методов / конструкторов. Так что, если вы смешаете их вместев один шаг, они обязательно уничтожат друг друга. Не удивительно, что они вызывают у вас головную боль ... :)

Основное правило для решения этих двух проблем - не смешивать их за один шаг. Это означает, что нам нужен промежуточный класс для решения задачи 1 и перегрузки потомков этого промежуточного класса. Что-то вроде этого:

type
  TComputer = class(TObject)
  private
    FCaller: TConstructorCaller;
  public
     constructor Create(Teapot: string=''); virtual;

     property Caller: TConstructorCaller read FCaller;
  end;

  TBaseCellphone=class(TComputer)
    constructor Create(Cup: Integer); virtual;
  end;

  TCellPhone = class(TBaseCellphone)
  protected
  public
    constructor Create(Cup: Integer); overload; override;
    constructor Create(Cup: Integer; Teapot: string); overload; virtual;
  end;

  TiPhone = class(TCellPhone)
  public
    constructor Create(Cup: Integer); reintroduce; overload;
    constructor Create(Handle: String); reintroduce; overload;
  end;

Из приведенного выше кода TBaseCellphone является промежуточным классом. В этом сценарии его задача состоит только в том, чтобы скрыть конструктор Create of TComputer. Обратите внимание, что выНЕ ДОЛЖЕН используйте ключевое слово overload здесь, иначе сокрытие будет отменено. Теперь, когда скрытие завершено, теперь вы можете свободно спамить ключевое слово перегрузки в его потомках, чтобы получить несколько конструкторов с одинаковыми именами.

Чтобы проверить, вы можете увидеть, что следующий код не скомпилируется:

   TCellPhone.Create('My Teapot');
 Sertac Akyuz07 окт. 2010 г., 20:37
@ Ян - Это не было бы ошибкой.Методы перегрузки: «... если метод redeclared имеет сигнатуру параметра, отличную от его предка, он перегружает унаследованный метод, не скрывая его».
 Luthfi08 окт. 2010 г., 04:01
Ян, перегрузка позволяет вам иметь несколько процедур или методов с одним и тем же именем. Им нужно только иметь разные параметры. Что касается вашего вопроса, я посмотрю, смогу ли я привести хороший пример.
 Ian Boyd07 окт. 2010 г., 17:48
я думаю, что нашел ошибку в Delphi.overload Ключевое слово делает конструктор предка все еще доступным - когда это не то, для чего он предназначен. Это должно позволить две перегрузки вTCellPhone, Как я могу использовать перегрузку, чтобы разрешить множественные перегрузки, но не позволить видимость методов от предка? IOW: как мне скрыть конструктор предка?

Ваш ответ на вопрос