Дельфы:Как скрыть конструкторы-предки?
-
28-09-2019 - |
Вопрос
Обновить: исправил вопрос на более простом примере, на который нет ответа первоначально принятый ответ
Дан следующий класс и его предок:
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.