Защищенный доступ и исключение наследования
Приватный член базового класса недоступен для производного класса. Из этого можно предположить, что для доступа к некоторому члену базового класса из производного класса этот член необходимо сделать открытым. Но если сделать член класса открытым, то он станет доступным для всего кода, что далеко не всегда желательно. Правда, упомянутое предположение верно лишь отчасти, поскольку в C# допускается создание защищенного члена класса. Защищенный член является открытым в пределах иерархии классов, но закрытым за пределами этой иерархии.
Защищенный член создается с помощью модификатора доступа protected. Если член класса объявляется как protected, он становится закрытым, но за исключением одного случая, когда защищенный член наследуется. В этом случае защищенный член базового класса становится защищенным членом производного класса, а значит, доступным для производного класса. Таким образом, используя модификатор доступа protected, можно создать члены класса, являющиеся закрытыми для своего класса, но все же наследуемыми и доступными для производного класса:

В данном примере класс MyClass наследуется классом ClassA, а его члены x, y и z объявлены как protected, и поэтому они доступны для метода LongVector(). Если бы члены x, y и z класса MyClass были объявлены как private, то они оказались бы недоступными для класса ClassA, и приведенный выше код нельзя было бы скомпилировать.
Аналогично состоянию public и private, состояние protected сохраняется за членом класса независимо от количества уровней наследования. Поэтому когда производный класс используется в качестве базового для другого производного класса, любой защищенный член исходного базового класса, наследуемый первым производным классом, наследуется как защищенный и вторым производным классом.
Хотя protected-поля данных могут нарушить инкапсуляцию, объявлять protected-методы достаточно безопасно (и полезно). При построении иерархий классов очень часто приходится определять набор методов, которые используются только производными типами.
Несмотря на всю свою полезность, защищенный доступ пригоден далеко не для всех ситуаций. Mодификатор доступа protected следует применять в том случае, если требуется создать член класса, доступный для всей иерархии классов, но для остального кода он должен быть закрытым. А для управления доступом к значению члена класса лучше воспользоваться свойством.
Ключевое слово sealed
В C# поддерживается еще одно ключевое слово — sealed, которое исключает наследование. Если класс помечен как sealed (запечатанный), компилятор не позволяет наследовать от него. Ниже приведен пример объявления класса типа sealed:
Как следует из комментариев в приведенном выше фрагменте кода, класс В не может наследовать класс А, потому что последний объявлен как sealed.
Чаще всего запечатывание имеет смысл при проектировании служебного класса. Например, в пространстве имен System определено множество запечатанных классов. В этом легко убедиться, открыв окно Object Browser в Visual Studio 2010 (через меню View (Вид)) и выбрав класс String, определенный в пространстве имен System внутри сборки mscorlib.dll:

Наиболее вероятная ситуация, когда может понадобиться пометить класс или метод как sealed — это когда класс или метод обеспечивает внутренние действия библиотеки, класса или других разрабатываемых классов, поэтому вы уверены, что любая попытка переопределить некоторую его функциональность приведет к нестабильности кода. Также можно помечать класс или метод как sealed из коммерческих соображений, чтобы предотвратить использование классов способом, противоречащим лицензионным соглашениям.
Диаграммы классов Visual Studio
Среда Visual Studio 2010 позволяет устанавливать между классами отношения «базовый-производный» визуально во время проектирования. Чтобы использовать этот аспект IDE-среды, первый шаг состоит во включении нового файла диаграммы классов в текущий проект. Для этого выберите в меню пункт Project — Add New Item (Проект — Добавить новый элемент) и затем пиктограмму Class Diagram (Схема классов):

После щелчка на кнопке Add (Добавить) появится пустая поверхность проектирования. Для добавления классов к диаграмме просто перетаскивайте каждый файл из окна Solution Explorer на эту поверхность. Также помните, что удаление элемента в визуальном конструкторе (за счет его выбора и нажатия клавиши <Delete>). не приводит к удалению ассоциированного исходного кода, а просто убирает элемент из поверхности проектирования:
Запрет наследования. Ключевое слово sealed . Особенности применения. Пример
В языке C# введено ключевое слово sealed , которое используется в двух случаях:
- когда нужно запретить наследование от некоторого класса. В многих иерархиях, классы, которые размещены на нижних уровнях могут быть обозначены как sealed ;
- когда нужно запретить переопределение некоторого метода в иерархии классов. Эта ситуация возможна, если в иерархии классов методы унаследованных классов переопределяют виртуальные методы базовых классов.
2. Применение ключевого слова sealed для класса. Общая форма. Пример
Общая форма использования ключевого слова sealed для класса, следующая:
- ClassName – имя класса, который нужно запретить наследовать.
Если из класса ClassName попробовать унаследовать другой класс, то возникнет ошибка на этапе компиляции. При этом, сам класс ClassName может быть унаследован от другого класса.
Например, в следующем коде
компилятор выдаст ошибку
3. Применение ключевого слова sealed для метода. Общая форма. Пример
Ключевое слово sealed может быть применено для метода также. Использование sealed для метода означает, что метод запрещено переопределять в унаследованных классах. Значит, такой метод должен быть объявлен с ключевым словом override . А это, в свою очередь, означает, что класс с sealed-методом должен наследовать другой базовый класс, который содержит метод с таким же именем.
Чтобы к методу класса применить ключевое слово sealed , нужно чтобы выполнялись следующие условия:
- класс должен быть унаследован от другого (базового) класса;
- в базовом классе должен быть объявлен метод, который переопределяется в данном (производном) классе. Этот метод базового класса также должен быть объявлен с ключевыми словами virtual или override (если базовый класс также унаследован).
Общая форма использования ключевого слова sealed для метода следующая:
- ClassName – имя класса, в котором объявлен sealed-метод с именем MethodName ;
- BaseClassName – имя класса, который есть базовым для класса ClassName . Запрет переопределения метода в классе предусматривает, что этот класс унаследован от другого базового класса, в котором объявлен одноименный переопределяемый метод. Поэтому, если для некоторого метода в классе нужно применить ключевое слово sealed , этот класс обязательно должен быть унаследован от другого класса;
- access_modifier – один из модификаторов доступа public , protected , internal , protected internal . Модификатор доступа private не может быть применен к sealed-методу;
- MethodName – имя метода, который объявляется как sealed . Данный метод должен быть объявлен с ключевым словом override . Это значит, что данный метод переопределяет одноименный метод базового класса BaseClassName .
Пример.
Объявляется иерархия классов A , B , C . В классе C объявляется метод, который запрещено переопределять.
Если из класса C попробовать унаследовать класс D , и в классе D объявить метод, который переопределяет метод Method() класса C как показано далее
то компилятор выдаст ошибку
Чтобы поправить ситуацию нужно выполнить одно из двух действий (в зависимости от поставленной задачи):
- убрать слово sealed перед именем метода в классе C ;
- поменять слово override на слово new перед именем метода в классе D .
4. Можно ли в sealed -классе объявить sealed метод?
Да, можно. В приведенном ниже примере объявляется sealed-класс и sealed-метод в этом классе.
Хотя класс B не может быть унаследован, компилятор такой код не запрещает.
Как использовать (в чем смысл) sealed?
То есть в этом примере я конкретно показал, что наследование не возможно.
В первом примере это показано не настолько явно. Там модификатор sealed был применен к наследуемому классу B и говорилось, что уже от класса B наследование не возможно. То есть какой то третий класс не сможет наследоваться.
И далее идет ещё один пример. (Вот он третий класс Z.)
Обратите внимание, тут sealed идет в связке с override.
Как я понимаю — sealed — это запечатанный. То есть запечатанное не наследуется, не изменяется и т.д.
Поставили sealed — всё «броня». Никто не изменит, унаследует (за некоторыми исключениями и приемами).
Но вот этот код не верен
Свойство Field_1 не может быть запечатанным т.к. не содержит модификатора override.
Почему? Я не хочу чтобы моё свойство было замещено или переопределено.
Вот ещё мой пример
Аналогично. Говорит — ставь sealed к override. То есть я могу запретить переопределение свойства classB.
А в чем проблема у classA? Я хочу чтобы его свойство никто не переопределил. Ставлю sealed.
И стандартной ошибки — невозможно. т.к. запечатано не вижу.
Почему для запечатывания требуется override? Почему запечатывание свойства я могу применить только ко второму классу?
- Вопрос задан более двух лет назад
- 4158 просмотров
- Вконтакте

- Вконтакте
Sealed переводится как «запечатанный, герметизированный». Запечатывается что именно?
1) Применение к объявлению класса. Первый пример показывает контекст применения ключевого слова. Функционал наследования запечатывается на первом же уровне наследования. В вашем контрпример не предоставляется новой информации для компилятора, поскольку на моменте компиляции компилятор сам может прийти к выводу, нужно ли при хранении объектов класса использовать указатель на таблицу виртуальных функций. Поэтому там слово sealed синтаксически верно, но лексически бесполезно.
2) Применение к объявлению члену класса. Запечатывание подразумевает наличие кое-чего, что можно запечатать. Именно — функционал наследования. Если вам нужно запечатать функционал наследования на каком-то уровне, вы это делаете. Если вы пытаетесь запечатать что-то на
уровне базового класса, то это в терминологии C# это невыражаемая мысль. Вы не должны использовать в таком случае наследование вообще (не объявлять virtual). Такую мысль могло бы выразить ключевое слово final (С++), но в C# его нет, в нём ООП используется немного в другом в контексте (где, грубо говоря, типы могут быть manged и unmanaged, и у программиста нет полного контроля над sizeof объектов типа).
Для чего нужен модификатор sealed в языке C#?
При применении к классу модификатор sealed запрещает другим классам наследовать от этого класса.
class A <>
sealed class B : A <>
Здесь класс B наследует от класса A, но ни какие классы не могут наследовать от класса B.
Модификатор sealed можно использовать для метода или свойства, которое переопределяет виртуальный метод или свойство в базовом классе. Это позволяет классам наследовать от вашего класса, запрещая им при этом переопределять определенные виртуальные методы или свойства.
- Чтобы предотвратить переопределение производных классов при определении новых методов или свойств, не назначайте их в качестве виртуальных (virtual). В противном случае программист будет видеть данный метод в списке методов, которые можно переопределить, но на этапе компиляции получит ошибку.
- Нельзя использовать модификатор abstract с sealed классом, поскольку абстрактный класс должен наследоваться классом, реализующим абстрактные методы или свойства. Это понятно, ведь основное назначение абстрактного класса в том, чтобы от него наследовались другие классы.
- При применении sealed модификатора к методу или свойству его необходимо всегда использовать с override.
А здесь все будет работать. Почему? Ведь мы переопределили метод, который переопределять то нельзя. Этому есть объяснение. Дело в том, что посредством модификатора new мы говорим, что не хотим переопределять унаследованный метод, а хотим создать свой собственный (новый метод) с таким же именем, который прячет одноименный метод предка. То есть в этом месте у нас перестает работать виртуальный механизм и появляется обычный метод.