Есть ли в C # понятие частного и защищенного наследования? - PullRequest
41 голосов
/ 28 августа 2008

Есть ли в C # понятие частного / защищенного наследования, и если нет, то почему?

C ++


class Foo : private Bar {
 public:
   ...
 }; 

C #


public abstract NServlet class : private System.Web.UI.Page
{
    // error "type expected"
}

Я реализую концепцию, подобную сервлету, на странице .aspx, и я не хочу, чтобы конкретный класс имел возможность видеть внутреннюю часть базы System.Web.UI.Page.

Ответы [ 10 ]

17 голосов
/ 28 августа 2008

C # разрешает только публичное наследование. C ++ допускает все три вида. Публичное наследование подразумевало тип отношений "IS-A", а частное наследование - тип отношений "реализовано в терминах". Так как многоуровневое (или составное) выполнение этого возможно более простым способом, частное наследование использовалось только тогда, когда это требовалось защищенными членами или виртуальными функциями, согласно Скотту Мейерсу в Effective C ++, Item 42.

Я полагаю, что авторы C # не считают необходимым дополнительный метод реализации одного класса в терминах другого.

7 голосов
/ 24 февраля 2010

Нет, это не так. Какая польза от такого ограничения?

Частное и защищенное наследование подходит для инкапсуляции (сокрытия информации). Защищенное * наследование поддерживается в C ++, хотя не в Java. Вот пример из моего проекта, где это было бы полезно.

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

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

Тем не менее, я думаю, что в C ++ (который, опять же, поддерживает частное и защищенное наследование) можно привести дочерний класс к родительскому и получить доступ к общедоступным членам родителя. (См. Также Пост Криса Карчера ) Тем не менее, защищенное наследование улучшает сокрытие информации. Если члены класса B1 должны быть действительно скрыты в других классах C1 и C2, это можно упорядочить, создав защищенную переменную класса B1 внутри C1 и C2. Защищенный экземпляр B1 будет доступен для детей от C1 и C2. Конечно, этот подход сам по себе не обеспечивает полиморфизм между C1 и C2. Но полиморфизм можно добавить (при желании), унаследовав C1 и C2 от общего интерфейса I1.

*** Для краткости будем использовать «защищенный» вместо «частный и защищенный».

** National Instruments Measurement Studio в моем случае.

  • Ник
6 голосов
/ 28 августа 2008

@ bdukes: Имейте в виду, что вы не действительно скрываете участника. E.g.:

class Base
{
   public void F() {}
}
class Derived : Base
{
   new private void F() {}
}

Base o = new Derived();
o.F();  // works

РЕДАКТИРОВАТЬ: Но это происходит так же, как частное наследование в C ++, что и требовал спрашивающий:)

5 голосов
/ 28 августа 2008

Вы можете скрыть унаследованные API от публичного просмотра, объявив того же члена в своем классе как private и используя ключевое слово new См. Скрытие наследования от MSDN.

3 голосов
/ 28 августа 2008

Если вы хотите, чтобы класс NServlet ничего не знал о странице, вы должны изучить использование шаблона Adapter. Напишите страницу, на которой будет размещен экземпляр класса NServlet. В зависимости от того, что именно вы делаете, вы можете написать широкий набор классов, которые знают только о базовом классе NServlet, не загрязняя ваш API членами страницы asp.net.

1 голос
/ 16 сентября 2015

Первое решение:

защищенный внутренний действует как общий в той же сборке и защищен в других сборках.

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

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

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


Проблема:

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


Окончательное решение:

Я вернулся к интерфейсу решение , чтобы скрыть методы .

Проблема с этим состояла в том, чтобы иметь возможность принудительно использовать интерфейс так, чтобы члены были скрыты ВСЕГДА скрыты, а затем определенно избегали ошибок.

Для принудительно использовать только интерфейс , просто сделать конструкторы защищенными и добавить статический метод для построения (я назвал его New). Этот статический метод New на самом деле является заводской функцией, и он возвращает интерфейс . Таким образом, остальная часть кода должна использовать только интерфейс!

1 голос
/ 23 июня 2012

Я знаю, что это старый вопрос, но я несколько раз сталкивался с этой проблемой при написании C #, и я хочу знать ... почему бы просто не использовать интерфейс?

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

Кажется, это C # -приемлемый способ делать подобные вещи.

Первый раз, когда я сделал это, я понял, что стандартная библиотека C # не имеет варианта словаря только для чтения. Я хотел предоставить доступ к словарю, но не хотел давать клиенту возможность изменять элементы в словаре. Итак, я определил «класс DictionaryEx : Dictionary , IReadOnlyDictionary , где V: IV», где K - тип ключа, V - тип действительного значения, а IV - интерфейс к типу V, который предотвращает изменения. Реализация DictionaryEx была в основном простой; единственной трудной частью было создание класса ReadOnlyEnumerator, но даже это не заняло много времени.

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

1 голос
/ 28 августа 2008

Возможно, вам нужен класс ServletContainer, который подключается к реализации NServlet. В моей книге не разрешать частное / защищенное наследование не так уж и сложно, и язык становится менее запутанным - с LINQ и т. Д. У нас уже есть достаточно материала, чтобы запомнить.

1 голос
/ 28 августа 2008

Нет, только публичное наследство.

0 голосов
/ 28 августа 2008

Нет, это не так. Какая польза от такого ограничения?

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