Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
voprosy_NEW.docx
Скачиваний:
5
Добавлен:
01.07.2025
Размер:
1 Мб
Скачать
☆

70. Наследование.

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

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

Для этого при объявлении производного класса указывается базовый класс.

class имя_производного_класса : имя_базового_класса { // тело класса }

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

Доступ к членам класса и наследование

Члены класса зачастую объявляются закрытыми, чтобы исключить их несанкционированное или незаконное использование. Но наследование класса не отменяет ограничения, накладываемые на доступ к закрытым членам класса. // Доступ к закрытым членам класса не наследуется.

// Этот пример кода не подлежит компиляции.

using System;

// Класс для двумерных объектов,

class TwoDShape {

double Width; // теперь это закрытая переменная

double Height; // теперь это закрытая переменная

public void ShowDim() { Console.WriteLine("Ширина и высота = " + Width + " и " + Height); } }

// Класс Triangle, производный от класса TwoDShape.

class Triangle : TwoDShape {

public string Style; // тип треугольника

// Возвратить площадь треугольника,

public double Area() { return Width * Height /2; // Ошибка! }

// Показать тип треугольника,

public void ShowStyle() { Console.WriteLine("Треугольник " + Style); }

}

Для преодоления данного ограничения в С# предусмотрены использование защищенных (protected) членов класса, а второй — в применении открытых свойств для доступа к закрытым данным. С помощью свойства можно ввести ограничения на доступ к значению переменной или же сделать ее доступной только для чтения. Если сделать свойство открытым, но объявить его базовую переменную закрытой, то этим свойством можно будет воспользоваться в производном классе, но нельзя будет получить непосредственный доступ к его базовой закрытой переменной.

Организация защищенного доступа

Используя модификатор доступа protected, можно создать члены класса, являющиеся закрытыми для своего класса, но наследуемыми и доступными для производного класса.

Аналогично состоянию public и private, состояние protected сохраняется за членом класса независимо от количества уровней наследования.

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

В иерархии классов допускается, чтобы у базовых и производных классов были свои собственные конструкторы.

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

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

Вызов конструкторов базового класса

конструктор_производного_класса{список_параметров) : base {список_аргументов) { // тело конструктора }

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

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

Наследование и сокрытие имен

В производном классе можно определить член с таким же именем, как и у члена его базового класса. В этом случае член базового класса скрывается в производном классе. Если член базового класса требуется скрыть намеренно, то перед его именем следует указать ключевое слово new, чтобы избежать появления предупреждающего сообщения. Это совершенно отдельное применение ключевого слова new, не похожее на его применение при создании экземпляра объекта. Ниже приведен пример сокрытия имени.

// Пример сокрытия имени с наследственной связью.

using System;

class A { public int i = 0; }

// Создать производный класс

class В : A {

new int i; // этот член скрывает член i из класса А

public В(int b) { i = b; // член i в классе В }

public void Show() { Console.WriteLine("Член i в производном классе: " + i); } }

class NameHiding {

static void Main() {

В ob = new В(2);

ob.Show(); } }

При вызове метода Show () для объекта типа В выводится значение переменной i, определенной в классе В, а не той, что определена в классе А.

Применение ключевого слова base для доступа к скрытому имени

base.член

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

С помощью ключевого слова base могут также вызываться скрытые методы.

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

Порядок вызова конструкторов

В иерархии классов конструкторы вызываются по порядку выведения классов: от базового к производному. Более того, этот порядок остается неизменным независимо от использования ключевого слова base. Если ключевое слово base не используется, то выполняется конструктор по умолчанию.

Ссылки на базовый класс и объекты производных классов

Переменная ссылки на объект класса одного типа, как правило, не может ссылаться на объект класса другого типа.

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

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

Один из самых важных моментов для присваивания ссылок на объекты производного класса переменным базового класса наступает тогда, когда конструкторы вызываются в иерархии классов.

Предотвращение наследования с помощью ключевого слова sealed

Для того чтобы предотвратить наследование класса, достаточно указать ключевое слово sealed перед определением класса. Класс не допускается объявлять одновременно как abstract и sealed, поскольку сам абстрактный класс реализован не полностью и опирается в этом отношении на свои производные классы, обеспечивающие полную реализацию.

Полиморфизм -это свойство, позволяющее одному интерфейсу получать доступ к общему классу действий( "один интерфейс — множество методов").

Ключевые слова virtual и override

Если базовый класс желает определить метод, который может быть (но не обязательно) переопределен в подклассе, он должен пометить его ключевым словом virtual.

Когда класс желает изменить реализацию деталей виртуального метода, он делает это с помощью ключевого слова override.

Переопределение виртуальных членов

При переопределении члена класса необходимо помнить типы всех параметров, а также соглашения о передаче параметров (ref, out и params). Во время переопределения метода DisplayStatusO необходимо прописать код (В VS 2010 это можно сделать автоматически):

public override void DisplayStats () {

base.DisplayStats () ; }

Запечатывание виртуальных членов

Ключевое слово sealed применяется к типу класса для предотвращения расширения другими типами его поведения через наследование. Иногда требуется не запечатывать класс целиком, а просто предотвратить переопределение некоторых виртуальных методов в производных типах.

Абстрактные классы

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

abstract partial class Employee { }

После этого попытка создать экземпляр класса Employee приведет к ошибке во время компиляции:

// Ошибка! Нельзя создавать экземпляр абстрактного класса!

Employee X = new Employee();

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]