Как запретить наследование от класса c
Перейти к содержимому

Как запретить наследование от класса c

  • автор:

Как запретить наследование класса в C#

Для предотвращения наследования от класса необходимо объявить его с модификатором sealed. Например, если мы не хотим чтобы от класса SomeClass можно было наследоваться, то объявляем его так:

sealed class SomeClass < // Объявление класса >

Отслеживать
ответ дан 21 окт 2010 в 21:13
Nicolas Chabanovsky Nicolas Chabanovsky
51.4k 87 87 золотых знаков 267 267 серебряных знаков 505 505 бронзовых знаков

В качестве альтернативы, можно запретить и создание экземпляров этого класса с помощью ключевого слова static (под капотом, будет использована пара модификаторов: abstract sealed ).

static class Helper < // допустимы лишь статические методы >

Отслеживать
ответ дан 12 апр 2015 в 0:17
Sergey Teplyakov Sergey Teplyakov
7,215 1 1 золотой знак 29 29 серебряных знаков 35 35 бронзовых знаков

    Важное на Мете
Похожие

Подписаться на ленту

Лента вопроса

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.9.3159

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Как запретить наследование от класса c

Запрет наследования

В этой статье, я хочу сказать пару слов о явном запрете наследования. Точнее о том, как можно запретить использование написанного Вами класса, в качестве базового для других. Я постараюсь доступно и коротко обосновать зачем, и вообще это нужно ли это делать. Материал этой статьи так или иначе связан с темой наследования классов, так что, если Вы еще не знакомы с механизмом наследования, то можете не читать эту статью, а перейти к изучению основ. Вот Вам ссылка на урок, посвященный наследованию классов в C#. А для тех кто уже в теме, я продолжу повествование…

И так, продолжим! Сначала я расскажу, зачем вообще запрещать использование наших классов в качестве базовых. На самом деле, всё просто, если мы изначально не разрабатываем наш класс для использования в качестве базового, то это уже повод запретить наследовать другие классы от него! Почему, да хотя бы по тому, что не подготовленный для «отцовства» класс, хорошим «отцом» скорее всего не станет!

Давайте вспомним, для чего обычно программисты используют механизм наследования ? Ну, в первую очередь, приходит в голову мысль о повторном использовании уже написанного кода. Т.е. мы имеем некий класс, но хотим расширит его функциональность. Однако, создавать еще один класс, повторно реализую функциональность первого и дополняя его новшествами мы не ходим (особенно, если не мы авторы первого класса и даже не знаем как реализована его функциональность), вместо этого мы просто «получаем по наследству» эту самую функциональность и всего лишь, дополняем её. Да, для этого можно использовать наследование, но совсем не обязательно! Можно решить эту задачу более гибким, и дешевым способом (пока поверьте на слово, потом, я напишу отдельную статью про то, как это сделать).

Ну и вторая цель использования наследования — это установка определенных отношений между базовым классом, и классом наследником. Объекты производных классов система может воспринимать и как объекты базового. Если объяснять на пальцах, то тигр является не только тигром, но еще и животным (но не каждое животное является тигром). Эти отношения между классами, выходят на сцену при использования так называемого принципа подстановки. Другими словами, при работе с объектами производных классом, через ссылку базового типа. Но эффективное применение упомянутого выше принципа будет невозможно, если автор базового класса не предусмотрел возможность использования своего детища в качестве базового для других классов. Например, не сделал какой-то метод класса виртуальным. Вот что я имел ввиду, когда говорил про неподготовленные для «отцовства» классы.

Если Вы не совсем понимаете о чем я сейчас говорил, изучите следующий урок.

Так вот, если Вы сами пишете весь код, то Вы просто можете договориться с собой, и не использовать какие-то классы в качестве базовых для других. Но в реальной практике, Вы, как разработчик потенциально базового класса можете быть даже не знакомы с программистом, решившим использовать Ваше творение в качестве базы для своего! И это может привести к неприятным сюрпризам для того человека. Но в C# есть возможность запретить использование класса в качестве родительского на этапе его разработки. И делается это очень просто, нужно добавить перед ключевым словом class ключевое слово sealed.

И всё, теперь теперь программист, не имеющий доступа к исходникам Вашего класса, не сможет использовать его как базовый для своих. А теперь покажу это на практике:

//"Отцом" уже не будет! sealed class SomeClass < //Тело класса >

В следующей статье, я, пожалуй, расскажу о том, как можно заменить наследование, если нам нужно просто повторное использование функциональности.

Добавить комментарий Отменить ответ

Для отправки комментария вам необходимо авторизоваться.

Запрет наследования: изолированные классы

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

Рис. 4.8. Расширенная иерархия служащих

Класс PTSalesPerson является классом, представляющим продавца, работающего на неполную ставку, и предположим, например, что вы хотите, чтобы никакой другой разработчик не мог создавать подклассы из PTSalesPerson. (В конце концов, какую еще неполную ставку можно получить на основе неполной ставки?) Чтобы не допустить возможности расширения класса, используйте ключевое слово C# sealed.

// Класс PTSalesPerson не сможет быть базовым классом.

public sealed class PTSalesPerson: SalesPerson

public PTSalesPerson(string fullName, int age, int empID, float currPay, string ssn, int numbOfSales): base (fullName, age, empID, currPay, ssn, numbOfSales)

// Логика конструктора…

// Другие члены…

Поскольку класс PTSalesPerson изолирован, он не может служить базовым Классам никакому другому типу. Поэтому при попытке расширить PTSalesPersоn вы получите сообщение об ошибке компиляции.

// Ошибка компиляции!

public class ReallyPTSalesPerson: PTSalesPerson

Наиболее полезным ключевое слово sealed оказывается при создании автономных классов утилит. Класс String, определённый в пространстве имен Sуstem, например, явно изолирован.

public sealed class string: object, IComparable, ICloneable, IConvertible, IEnumerable

Поэтому вы не сможете создать новый класс, производный от System.String:

// Снова ошибка!

public class MyString: string

Если вы хотите создать новый класс, использующий функциональные возможности изолированного класса, единственным вариантом будет отказ от классического наследования и использование модели локализации/делегирования (известной еще как отношение локализации, «has-a»).

Читайте также

8.17.6 Изолированные маршруты BGP

8.17.6 Изолированные маршруты BGP Маршрут исключается, если:? Он присутствует в списке изолированных маршрутов из сообщения об изменениях.? В изменениях приведен заменяющий маршрут.? Система BGP завершает такое соединение. Все маршруты через эту систему становятся

Проблема наследования

Проблема наследования Если существует необходимость наследовать от класса Singleton, то следует придерживаться определенных правил.Во-первых, класс-наследник должен переопределить метод Instance(), так, чтобы создавать экземпляр производного класса. Если не предполагается, что

Глава 8. Изучение наследования

Глава 8. Изучение наследования НаследованиеНаследованием (inheritance) называется такое отношение между классами, когда один класс использует часть структуры и/или поведения другого или нескольких классов. При наследовании создается иерархия абстракций, в которой подкласс

Правило 39: Продумывайте подход к использованию закрытого наследования

Правило 39: Продумывайте подход к использованию закрытого наследования В правиле 32 показано, что C++ рассматривает открытое наследование как отношение типа «является». В частности, говорится, что компиляторы, столкнувшись с иерархией, где класс Student открыто наследует

Правило 40: Продумывайте подход к использованию множественного наследования

Правило 40: Продумывайте подход к использованию множественного наследования Когда речь заходит о множественном наследовании (multiple inheritance – MI), сообщество разработчиков на C++ разделяется на два больших лагеря. Одни полагают, что раз одиночное исследование (SI) – это хорошо,

Второй принцип: поддержка наследования в C#

Второй принцип: поддержка наследования в C# Теперь, после исследования различных подходов, позволяющих создавать классы с хорошей инкапсуляцией, пришло время заняться построением семейств связанных классов. Как уже упоминалось, наследование является принципом ООП,

Цепочка наследования типа Page

Цепочка наследования типа Page Как вы только что убедились, готовый генерируемый класс, представляющий файл *.aspx, получается из System.Web.UI.Page. Подобно любому базовому классу, этот тип обеспечивает полиморфный интерфейс всем производным типам. Однако тип Page является не

18.6. Пример множественного виртуального наследования A

18.6. Пример множественного виртуального наследования A Мы продемонстрируем определение и использование множественного виртуального наследования, реализовав иерархию шаблонов классов Array (см. раздел 2.4) на основе шаблона Array (см. главу 16), модифицированного так, чтобы он

19. Применение наследования в C++

19. Применение наследования в C++ При использовании наследования указатель или ссылка на тип базового класса способен адресовать объект любого производного от него класса. Возможность манипулировать такими указателями или ссылками независимо от фактического типа

2.2.4. Типы сущностей и иерархия наследования

2.2.4. Типы сущностей и иерархия наследования Как было указано выше, связи определяют, является ли сущность независимой или зависимой. Различают несколько типов зависимых сущностей.Характеристическая — зависимая дочерняя сущность, которая связана только с одной

Просмотр дерева наследования классов

Просмотр дерева наследования классов ClassView предоставляет очень интересную и полезную возможность просмотра дерева наследования классов приложения. Для этого выберите название интересующего вас класса из списка классов и откройте временное меню, нажав правую кнопку

Смысл наследования

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

Отложенные классы как частичные интерпретации: классы поведения

Отложенные классы как частичные интерпретации: классы поведения Не все отложенные классы так близки к АТД как STACK. В промежутке между полностью абстрактным классом, таким как STACK, в котором все существенные компоненты отложены, и эффективным классом, таким как FIXED_STACK,

Примеры множественного наследования

Примеры множественного наследования Множественное наследование это, по сути, прямое приложение уже рассмотренных принципов наследования, — класс вправе иметь произвольное число родителей. Однако, изучая этот вопрос более внимательно, можно обнаружить две интересные

Лекция 16. Техника наследования

Лекция 16. Техника наследования Наследование — ключевая составляющая ОО-подхода к повторному использованию и расширяемости. В этой лекции нам предстоит исследовать новые возможности, разнородные, но демонстрирующие замечательные следствия красоты базисных идей.

Глобальная структура наследования

Глобальная структура наследования Ранее мы уже ссылались на универсальные (universal) классы GENERAL и ANY, а также на безобъектный (objectless) класс NONE. Пришло время пояснить их роль и представить глобальную структуру

Как запретить наследование от класса c

Почему следующая программа не компилируется:

using System; namespace HelloApp < class Program < static void Main(string[] args) < Person tom = new Employee(); Console.ReadKey(); >> internal class Person < >public class Employee : Person < >>

Производный класс не может иметь больщий уровень доступа или быть более доступным, чем базовый класс. Здесь же базовый класс Person имеет модификатор internal, а производный класс Employee — модификатор public. Таким образом, класс Employee является более доступным чем Person.

Даны следующие классы:

class Person < string name; int age; public Person() < >public Person(string name) : this(name, 18) < >public Person(string name, int age) < this.name = name; this.age = age; >> class Employee : Person < string company; public Employee() < >public Employee(string name, int age, string company): base(name, age) < this.company = company; >public Employee(string name, string company) : base(name) < this.company = company; >>

Допустим, мы создаем объект класса Employee следующим образом:

Employee tom = new Employee("Tom", "Microsoft");

Какие конструкторы и в каком порядке в данном случае будет выполняться?

Порядок выполнения конструкторов:

  1. System.Object.Object()
  2. Person(string name, int age)
  3. Person(string name)
  4. Employee(string name, string company)

Как запретить наследование от класса?

Указать при определении класса модификатор sealed

Что выведет на консоль следующая программа и почему?

class Auto // легковой автомобиль < public int Seats < get; set; >// количество сидений public Auto(int seats) < Seats = seats; >> class Truck : Auto // грузовой автомобиль < public decimal Capacity < get; set; >// грузоподъемность public Truck(int seats, decimal capacity) < Seats = seats; Capacity = capacity; >> class Program < static void Main(string[] args) < Truck truck = new Truck(2, 1.1m); Console.WriteLine($"Грузовик с грузоподъемностью тонн"); Console.ReadKey(); > >

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

Что выведет на консоль следующая программа и почему?

class Auto // легковой автомобиль < public int Seats < get; set; >// количество сидений public Auto() < Console.WriteLine("Auto has been created"); >public Auto(int seats) < Seats = seats; >> class Truck : Auto // грузовой автомобиль < public decimal Capacity < get; set; >// грузоподъемность public Truck(decimal capacity) < Seats = 2; Capacity = capacity; Console.WriteLine("Truck has been created"); >> class Program < static void Main(string[] args) < Truck truck = new Truck(1.1m); Console.WriteLine($"Truck with capacity "); Console.ReadKey(); > >

Консольный вывод программы:

Auto has been created Truck has been created Truck with capacity 1,1

При создании объекта производного класса вначале вызываются конструкторы базового класса. Поскольку в данном случае консструктор Truck явным образом не вызывает ни одного конструктора, то неявно вызывается конструктор базового класса по умолчанию, который выводит строку «Auto has been created». Затем собственно выполняется конструктор производного класса, который выводит строку «Truck has been created».

Что выведет на консоль следующая программа и почему?

class Person < public string Name < get; set; >= "Ben"; public Person(string name) < Name = "Tim"; >> class Employee : Person < public string Company < get; set; >public Employee(string name, string company) : base("Bob") < Company = company; >> class Program < static void Main(string[] args) < Employee emp = new Employee("Tom", "Microsoft") < Name = "Sam" >; Console.WriteLine(emp.Name); // Ben Tim Bob Tom Sam Console.ReadKey(); > >

Программа выведет на консоль имя «Sam». Вне зависимости от того, в каком порядке и какие конструкторы вызываются, инициализатор производного класса будет выполняться в самую последнюю очередь. Поэтому финальное значение свойства Name будет равно «Sam».

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *