Как добавить защищенный виртуальный метод в класс «Компонент», чтобы его можно было вызывать из «Композит»?
В качестве конкретного примера, посмотрите на код ниже, и, пожалуйста, скажите мне, как избежать ошибки компилятора в DxCompositeShape.ComputeSize
,
abstract class DxShape // this is the Component
{
public abstract void Paint();
protected abstract void ComputeSize();
}
class DxCompositeShape : DxShape // this is the Composite
{
public readonly IList<DxShape> Shapes = new List<DxShape>();
public override void Paint()
{
this.ComputeSize();
}
protected override void ComputeSize()
{
foreach (DxShape sh in Shapes)
{
sh.ComputeSize(); // compiler error CS1540
}
// and some other logic here
}
}
РЕДАКТИРОВАТЬ: я изменил свой образец, поэтому у меня есть ComputeSize
вместо Init
(люди предполагают, что Init всегда можно вызвать в конструкторе).
Создать не виртуальную функцию Initialise()
в базовом классе, который вызывает Init
например:
abstract class DxShape
{
protected void Initialise()
{
Init();
}
protected abstract void Init();
//...
}
Как указано в комментариях ниже, Initialise
должен быть открыт или статичен (только в C #), он может оставаться защищенным в C ++.
В C ++ вы можете сделать Init частным и получать к нему доступ только через вызовы Initialise
, Смотрите не виртуальный интерфейс http://en.wikipedia.org/wiki/Non-virtual_interface_pattern
Ты не можешь Защищенный член другого объекта может быть вызван только в том случае, если компилятор видит, что рассматриваемый объект того же типа, что и ваш текущий объект. По сути, «защищенный» означает, что «производные классы могут использовать этот член в своем собственном классе.
Основная проблема здесь заключается в том, что вы хотите, чтобы некоторые привилегированные классы («композиты») могли вызывать метод внешних классов («компонентов»), который базовый класс объявляет только для использования производных классов в их собственной реализации.
Вы можете сделать Init
внутренний, если все композиты находятся в одном пакете. Или может сделать подкласс компонента, который наследуют все композиты, и сделать этот конкретный класс привилегированным для вызова Init
на все компоненты. В C ++ вы бы делали это с объявлениями друзей. В C # осторожное использование внутреннего доступа, вероятно, является правильным решением.