Foreversoft.ru

IT Справочник
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Наследование си шарп

Основы наследования

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

В языке C# класс, который наследуется, называется базовым, а класс, который наследует, — производным. Следовательно, производный класс представляет собой специализированный вариант базового класса. Он наследует все переменные, методы, свойства и индексаторы, определяемые в базовом классе, добавляя к ним свои собственные элементы.

Поддержка наследования в C# состоит в том, что в объявление одного класса разрешается вводить другой класс. Для этого при объявлении производного класса указывается базовый класс. При установке между классами отношения «является» строится зависимость между двумя или более типами классов. Базовая идея, лежащая в основе классического наследования, заключается в том, что новые классы могут создаваться с использованием существующих классов в качестве отправной точки:

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

Как видите класс CSharp получает доступ к полям и методам класса ProfessorWeb. Всегда помните, что наследование предохраняет инкапсуляцию, а потому приватные члены никогда не могут быть доступны через ссылку на объект. Т.е. поле inf из примера не может быть доступно для вызова с помощью экземпляра класса obj.

Для любого производного класса можно указать только один базовый класс. В C# не предусмотрено наследование нескольких базовых классов в одном производном классе. (В этом отношении C# отличается от С++, где допускается наследование нескольких базовых классов. Данное обстоятельство следует принимать во внимание при переносе кода С++ в C#.) Тем не менее можно создать иерархию наследования, в которой производный класс становится базовым для другого производного класса. (Разумеется, ни один из классов не может быть базовым для самого себя как непосредственно, так и косвенно.) Но в любом случае производный класс наследует все члены своего базового класса, в том числе переменные экземпляра, методы, свойства и индексаторы.

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

BestProg

Наследование. Использование конструкторов в классах при наследовании. Ключевое слово base . Примеры

Содержание

1. Порядок вызова конструкторов классов, которые образовывают иерархию

При создании экземпляра (объекта) класса первым вызывается конструктор этого класса. Если класс B есть производным от базового класса A , то сначала вызывается конструктор базового класса A , а затем конструктор производного класса B . Если классы образовывают иерархию из нескольких уровней наследования, то сначала будут вызываться конструкторы классов высших уровней в виде цепочки вплоть до вызова конструкторов более низких уровней.

На рисунке 1 изображена последовательность вызова конструкторов в случае наследования трех классов с именами A , B , C . Как видно из рисунка, первым всегда вызывается конструктор базового класса A . Вторым всегда вызывается конструктор класса B , который размещается на среднем уровне иерархии. Последним будет вызван конструктор класса C , который находится на нижнем уровне иерархии.

Рисунок 1. Демонстрация порядка вызова конструкторов в случае наследования трех классов

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

2. Ключевое слово base . Необходимость применения. Общая форма

Если классы образовывают иерархию, то в производном классе возникает необходимость обратиться к элементу базового класса. В языке C# для таких случаев предусмотрено использование ключевого слова base. Если в базовом классе есть скрытые элементы (объявленные как private ), то к этим элементам нет доступа с помощью ключевого слова base .

Общая форма использования ключевого слова base в методе производного класса, следующая:

  • class_element – элемент базового класса, который не является скрытым (перед которым не стоит модификатор доступа private ). Элементом базового класса может быть конструктор, метод (функция), свойство, поле данных. Для любого из этих элементов предусмотрен отдельный синтаксис использования (смотрите пункты ниже).
Читать еще:  Задачи паскаль 9 класс с решением
3. Вызов конструктора базового класса с использованием средства base . Общая форма. Примеры

Конструктор базового класса может быть вызван явным образом из конструктора производного класса. Для этого, при объявлении конструктора производного класса, нужно использовать ключевое слово base . Общая форма такого объявления следующая:

  • ClassName – имя конструктора производного класса;
  • parameters1 – параметры конструктора базового класса. Чтобы компилятор не выдавал ошибки, в базовом классе должен быть явно объявлен конструктор с точно такими же параметрами;
  • parameters2 – параметры конструктора производного класса.

первым вызовется конструктор базового класса с помощью вызова

затем вызывается тело конструктора ClassName() .

3.1. Пример вызова конструктора базового класса с помощью ключевого слова base . Используется иерархия из трех классов

Пример демонстрирует наследование трех классов A , B , C . Класс A есть базовым для класса B . В свою очередь, класс B есть базовым для класса C .

Как видно из вышеприведенного кода, В классе из конструктора класса B вызывется конструктор класса A с помощью строки

Аналогично в классе C из конструктора C(int) вызывается конструктор класса B

Результат работы программы

3.2. Вызов конструктора базового класса с помощью base . Пример классов Human=>Worker

Задан базовый класс Human (Человек). В классе заданы следующие элементы:

  • внутреннее поле name , реализующее фамилию и имя человека;
  • конструктор с 1 параметром Human(string) ;
  • свойство Name . Используется для доступа к внутреннему полю name .

Из класса Human наследуется класс Worker (Рабочий). В классе Worker реализованы следующие элементы:

  • внутреннее поле – дата принятия на работу date в формате строки;
  • внутреннее поле – должность position ;
  • конструктор с тремя параметрами Worker(string, string, string) , устанавливающий внутренние поля производного класса Worker и базового класса Human . Для вызова конструктора базового класса используется ключевое слово base ;
  • свойство Date для доступа к внутреннему полю date ;
  • свойство Position для доступа к внутреннему полю position.

Текст программы, созданной по шаблону Console Application следующий:

Результат работы программы

4. В каких случаях не обязательно использовать ключевое слово base для вызова конструктора базового класса? Пример

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

Пример. Даны два класса с именами A , B . В классе A объявлены 2 конструктора:

  • без параметров A() ;
  • с параметром A(int) .

Класс B есть производный от класса A . В классе B , при объявлении конструктора (любого ) не обязательно использовать ключевое слово base , так как в классе A объявлен конструктор без параметров.

Если в классе A() убрать объявление конструктора без параметров

то компилятор выдаст ошибку

5. Пример явного вызова конструктора базового класса с помощью ключевого слова base без указания параметров

Если в базовом классе A объявлен конструктор без параметров A() , то допускается указание ключевого слова base без параметров.

Например.

6. Неявный вызов конструкторов базовых классов на примере иерархии из трех классов.

Пример демонстрирует иерархию вызовов конструкторов без ключевого слова base для классов A , B , C . Ключевое слово base используется неявно.

Наследование в C#

Всем доброго времени суток. На связи Алексей Гулынин. В прошлой статье вы узнали немного о том, что такое делегаты в C#. В данной статье я бы хотел рассказать про наследование в C#. Простыми словами, «Наследование» означает то, что мы создаём класс на основе другого. Получается, у нас есть родительский класс и дочерний класс, который наследует все поля и методы родительского класса. Для того, чтобы понять, что такое наследование и для чего его нужно использовать, вернёмся к понятию объекта.

Объект представляет собой некую абстрактную сущность. Допустим мы хотим создать класс «Animal» (Животное). Но животных же существует великое множество и вряд ли мы одним классом сможем описать их всех. В классе «Animal» мы можем создать поля и методы, присущие всем животным. Например, полями общими для всех животных могут быть «Вес», «Средняя продолжительность жизни», «Имеется хвост или нет». Методом может быть «eat()» (кушать), ведь все же животные питаются. От такого общего класса мы можем создать дочерний класс, который расширяет родительский класс. Например, класс «Dog» (собака) может расширять класс «Animal» уже конкретными полями и методами, которые соответствуют именно собакам.

Читать еще:  Экспонента в степени паскаль

Отношение наследования — это отношение перехода от более общей абстракции к более конкретной.

В C# наследование является одиночным, то есть нельзя наследоваться от двух и более классов. Наследование определяется через «:».

Интересный момент: если вы пишете обычный класс, который не имеет родителя, то, по умолчанию, этот класс является наследником класса «Object». Класс «Object» является родителем абсолютно для всех классов в .NET.

Немного поговорим про понятия, так или иначе связанные с наследованием.

Абстрактный класс — это класс, объекты которого нельзя создавать, т.е. нельзя будет использовать ключевое слово «new». Абстрактные классы используются при наследовании и используются как прародители к другим классам (реальным, не абстрактным). Т.е. в нашем примере можно класс «Animal» пометить как «abstract». Абстрактным может быть также и метод (это метод без реализации). Если в классе присутствует хотя бы один абстрактный метод, то и сам класс обязан быть абстрактным. В обратную сторону правило не действует.

С помощью ключевого слова «sealed» можно запретить создавать наследников от класса. Пример: класс «String». От этого класса мы не сможем создать наследников. Применение ключевого слова «sealed» к методу означает, что мы запрещаем переопределение этого метода в классах-наследниках.

Ключевое слово «virtual» применяется только к методам, и используется для того, чтобы превратить метод в виртуальный. Это делается для того, чтобы метод можно было переопределить в классах-наследниках. Переопределение метода означает, что мы внутри класса-наследника создаём метод, у которого заголовок полностью совпадает с заголовком метода класса-родителя. При этом в классе-наследнике нужно указать ключевое слово «override», чтобы явно указать, что мы переопределяем метод.

Давайте на примере разберем всё то, что мы только что узнали. Для простоты все поля и методы сделаем публичными (в реальных программах так, конечно, делать не нужно):

Конструкторы при наследовании.

Конструкторы не наследуются. Если в родительском классе определены различные конструкторы, то при наследовании эти конструкторы будут недоступны у класса-наследника. Несмотря на то, что конструкторы не наследуются — они автоматически вызываются. Когда вызывается конструктор класса-наследника автоматом вызывается конструктор класса-родителя. По умолчанию будет вызываться дефолтный конструктор класса-наследника без параметров. Обращаю ваше внимание на то, что если такого конструктора без параметров не будет, то будет получена ошибка при компиляции.

Если мы хотим, чтобы вызывался другой родительский конструктор, то это можно указать с помощью ключевого слова «base» .

С помощью «base» также можно вызывать родительский метод.

Разберем на эту тему вот такой пример: пусть имеется родительский класс «Degree», имеющий одной поле «degrees» и один метод, который возвращает значение данного поля. Создадим дочерний класс «Radiance», который, используя метод родительского класса, возвращает градусы, переведенные в радианы:

Напоследок, обобщу особенности наследования:

  • Ключевые слова «sealed» и «static» (статический класс, про него поговорим в отдельной статье) запрещают наследование
  • Если в базовом классе определен какой-то метод «abstract», то базовый класс тоже должен быть абстрактным. В классе-наследнике такой абстрактный метод нужно переопределить. Абстрактный метод, по умолчанию, является виртуальным.
  • При проектировании программы важным является понимание того, что от чего можно унаследовать, а что нельзя. Для проверки условия наследования используется слово «является». В нашем примере: «Собака является животным? — является», «Питбуль является собакой? — является». А вот наоборот лучше не делать (технически конечно можно, но программы лучше сразу проектировать правильно), «Животное является собакой? — не является». Поэтому класс «Animal» от класса «Dog» наследовать нельзя.

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

На связи был Алексей Гулынин, оставляйте свои комментарии, увидимся в следующих статьях.

C#: классы, структуры, наследование

Классы и структуры в C# относятся к пользовательским типам (Custom types), т.е. типам, введенным разработчиком.

Классы

Класс — самый общий ссылочный тип. Простейшее объявление класса выглядит следующим образом:

Перед ключевым словом class могут присутствовать атрибуты (attributes) и модификаторы класса (class modifiers): public , internal , abstract , sealed , static , unsafe и partial . После названия класса могут указываться параметры обобщенного типа (generic type parameters), базовый класс (base class) и интерфейсы (interfaces). Внутри фигурных скобок могут располагаться члены класса (сlass members): методы (methods), свойства (properties), индексаторы (indexers), события (events), поля (fields), конструкторы (constructors), перегруженные операторы (overloaded operators), вложенные типы (nested types) и файналазер (finalizer).

Читать еще:  Тернарный оператор си шарп

Поля (Fields)

Поле — это переменная, являющаяся членом класса или структуры.

У поля может быть модификатор readonly , который предотвратит изменение поля после того как оно будет создано. Такому полю значение может быть присвоено только при объявлении или во внутреннем конструкторе типа.

Инициализировать поля не обязательно. Поля, которым не присвоено значение, принимают значение по умолчанию ( 0 , , null , false ). Инициализация полей запускается до выполнения конструктора, в том порядке, в котором следуют поля.

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

Методы (Methods)

Метод представляет собой действие, состоящие из ряда инструкций. При вызове метод может принимать входные данные в виде параметров и возвращать данные в точку вызова в виде возвращаемого типа. Метод может возвращать тип void , т.е. не возвращать в точку вызова никакого значения. Метод также может возвращать данные в точку вызова с помощью параметров ref и out .

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

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

Конструкторы

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

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

В вызываемый конструктор можно передавать выражения, однако в таком выражении не должна присутствовать ссылка на this (например, чтоб вызвать метод объекта), но допустимо вызывать статические методы.

Автоматический конструктор. В том случае (и только в том случае) если для класса не задан ни один конструктор компилятор C# автоматически генерирует публичный (public) конструктор без параметров.

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

Непубличный конструктор. Конструктор необязательно должен быть публичным (public). Самый распространенный пример, когда может понадобиться непубличный конструктор — необходимость контролировать создание экземпляров класса через вызов статического метода. Такой класс сначала проверяет наличие уже созданного объекта и если он уже создан — возвращает его, если нет — создает новый. Также такой метод может возвращать определенный подкласс исходя из входных аргументов.

Инициализаторы объекта

Чтобы упростить инициализацию объекта, все его доступные поля и свойства могут быть инициализированы с помощью инициализатора объекта сразу после создания объекта.

Ссылка this

Ссылка this указывает на сам экземпляр объекта.

Ссылка this также разрешает неоднозначность между локальными переменными или параметрами и полями объекта.

Ссылку this допустимо использовать только с нестатичными членами класса или структуры.

Свойства (Properties)

Внешне свойства ничем не отличаются от полей, но внутри самого класса они отличаются тем, что подобно методам содержат логику. Свойства определяются также как поля, но с добавлением блока get/set .

get и set — это средства доступа к свойствам (accessors). get выполняется при чтении свойства. Он должен возвращать значение того же типа, что и само свойство. set выполняется когда свойству присваивается значение. Оно имеет скрытый параметр value того же типа, что и само свойство.

Хотя доступ к полям и свойствам осуществляется одинаково, свойства в отличие от полей предоставляют полный контроль над процессом присвоения и получения значений (например, метод set может выбрасывать исключения и т.д.).

Если из средств доступа установлен только get , свойство будет доступно только для чтения (read-only), а если только set — только для записи (write-only). Обычно для свойства создается частное поле, в котором сохраняются данные, но это не обязательно: свойство может возвращать результаты расчета других данных.

Как уже отмечалось, самое распространенное назначение свойств — получение и присвоение значения частным полям того же типа что и свойство. Это можно сделать автоматически, используя объявление автоматических свойств (automatic property).

Ссылка на основную публикацию
Adblock
detector