Защищенный доступ и исключение наследования
Организация защищенного доступа
Приватный член базового класса недоступен для производного класса. Из этого можно предположить, что для доступа к некоторому члену базового класса из производного класса этот член необходимо сделать открытым. Но если сделать член класса открытым, то он станет доступным для всего кода, что далеко не всегда желательно. Правда, упомянутое предположение верно лишь отчасти, поскольку в C# допускается создание защищенного члена класса. Защищенный член является открытым в пределах иерархии классов, но закрытым за пределами этой иерархии.
Защищенный член создается с помощью модификатора доступа protected. Если член класса объявляется как protected, он становится закрытым, но за исключением одного случая, когда защищенный член наследуется. В этом случае защищенный член базового класса становится защищенным членом производного класса, а значит, доступным для производного класса. Таким образом, используя модификатор доступа protected, можно создать члены класса, являющиеся закрытыми для своего класса, но все же наследуемыми и доступными для производного класса:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class MyClass { // Члены закрытые для класса Program // но открытые для класса ClassA protected int x, y, z; } class ClassA : MyClass { public ClassA (int x, int y, int z) { this.x = x; this.y = y; this.z = z; } // Данный метод использует защищенные члены класса MyClass public double LongVector() { return Math.Sqrt(x*x + y*y + z*z); } } class Program { static void Main() { ClassA obj = new ClassA(x: 12, y: 5, z: 6); Console.WriteLine("Длина вектора равна: {0:#.##}",obj.LongVector()); Console.ReadLine(); } } }
В данном примере класс 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 class А { // ... // Следующий класс недопустим. class В : А { // ОШИБКА! Наследовать класс А нельзя //... }
Как следует из комментариев в приведенном выше фрагменте кода, класс В не может наследовать класс А, потому что последний объявлен как 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>). не приводит к удалению ассоциированного исходного кода, а просто убирает элемент из поверхности проектирования:
Комментарии