Вопрос

Обновить: исправил вопрос на более простом примере, на который нет ответа первоначально принятый ответ

Дан следующий класс и его предок:

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 конструктора:

  • Чашка:Целое число
  • Чашка:Целое число;Чайник:строка
  • Чайник:строка = "

Что мне делать, чтобы TCellPhone так что конструктор - предок (Teapot: string = '') не отображается, оставляя только объявленные конструкторы:

  • Чашка:Целое число
  • Чашка:Целое число;Чайник:строка

Примечание:Обычно простой акт имея конструктор-потомок скрывает предка:

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); virtual;
end;
  • Чашка:Целое число

И если вы желанный чтобы сохранить как конструктор-предок , так и потомок , вы должны пометить потомок как overload:

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
end;
  • Чашка:Целое число
  • Чайник:строка = "

В примере кода этого вопроса Delphi ошибочно принимает мой overload ключевые слова:

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

думать , что:

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

Как мне скрыть конструктор-предок?

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


Попытка ответа (неудачная)

i пытался пометка конструкторов-потомков с помощью reintroduce (возвращаюсь к своему режиму случайного добавления ключевых слов, пока это не сработает):

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

Но это не сработало, все три конструктора по-прежнему видны.:(


Оригинальный Вопрос

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

TEniac = class(TObject)
   constructor Create(PowerCord: TPowerCord=nil); //calls inherited Create

TComputer = class(TEniac) ...
   constructor Create(PowerCord: TPowerCord=nil); //calls inherited Create(nil)

TCellPhone = class(TComputer)
   constructor Create(sim: TSimChip; UnlockCode: Integer); //calls inherited Create(nil)

TiPhone = class(TCellPhone)
   constructor Create(sim: TSimChip); //calls inherited Create(sim, 0)

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

Теперь, когда кто-то использует TiPhone я не хочу, чтобы они даже были в состоянии видишь конструктор из TEniac:

iphone := TiPhone.Create(powerCord);

Еще хуже:если они вызывают этот конструктор, они полностью пропускают мой конструктор и все, что делается между ними.Довольно легко вызвать неправильный конструктор, все они видны в IDE code-completion и будут скомпилированы:

TiPhone.Create;

и они получают совершенно недопустимый объект.

я мог бы измениться TCellPhone чтобы создать исключение в этих конструкторах:

TCellPhone.Create(PowerCord: TPowercord)
begin
   raise Exception.Create('Don''t use.');
end;

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

Это было полезно?

Решение

Невозможно сделать, чтобы конструкторы были введены в предку недоступным для создания производного класса в Delphi, потому что вы всегда можете сделать это:

type
  TComputerClass = class of TComputer;

var
  CellPhoneClass: TComputerClass = TCellPhone;
  CellPhone : TCellPhone;
begin
  CellPhone := CellPhoneClass.Create('FUBAR') as TCellPhone;
end;

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

Лучше всего вы можете сделать:

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

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

В этом случае код выше, по крайней мере, звонить TCellPhone.Create(Teapot: string='') вместо TComputer.Create(Teapot: string='')

Другие советы

Если я правильно помню, то reintroduce должно помочь для виртуальный методы.

Тот Самый вновь ввести директива подавляет предупреждения компилятора о скрытии ранее объявленных виртуальных методов.Используйте reintroduce, когда вы хотите скрыть унаследованный виртуальный метод с помощью нового.

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

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

TIndermediateComputer = class(TComputer)
protected
  // hide the constructor
  constructor Create;
end;

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

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

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;

TComputer.Create всегда будет виден из TCellPhone. Отказ Вы можете предотвратить TComputer.Create от неприятно под названием объявил TCellPhone.Create с той же подписью.

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

Тогда до тех пор, пока у вас нет звонка inherited в тело TCellPhone.Create(Teapot: string='') Вы можете предотвратить TComputer.Create от названия в TCellPhone и его потомки. Последующий:

TCellphone.Create;
TCellphone.Create('MyPhone');

Будет решать реализации TCellphone.

Кроме того:

TiPhone = class(TCellPhone)
    constructor Create;
end;

constructor TiPhone.Create;
begin
  inherited;
end;

Вызовут TCellPhone.Create и не TComputer.Create.

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

TCellPhone = class(TComputer)
   constructor Create(PowerCord: TPowerCord=nil); deprecated;
   constructor Create(sim: TSimChip; UnlockCode: Integer); //calls inherited Create(nil)

Кроме того, используйте переопределение или реинзрот по мере необходимости.

Вы хотите повторно создать конструктор:

TiPhone = class(TCellPhone)
    constructor Create(sim: TSimChip); reintroduce;

Видеть TComponent.Create В исходный код Delphi для реального примера этого.

Я знаю, что это 5 лет тема, но все же это может помочь кому-то. Единственный способ скрыть конструктора предка - переименовать один из двух методов создания для чего-то другого и удалить необходимость перегрузка Директива. Это выглядит странно, но это единственный путь. По крайней мере, в более старых версиях Delphi. Я не знаю, возможно, теперь в версиях XE XXX.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top