класса. Таким образом, получаем цепочку наследования: класс А является

базовым для класса В, а класс В является базовым для класса С. Это пример

многоуровневогонаследования, которое, в отличие от многократного (или

множественного) наследования, в С# разрешено и широко используется

на практике.

Многократное наследование — это наследование, при котором один

класс создается сразу на основе нескольких базовых классов. Так де-

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

класса. Так в C# делать можно. Этим мы и воспользовались выше.

84

Глава 2. Классы и объекты

В главном методе программы мы объявляем три объектные переменные: переменная objA класса A, переменная objB класса B и объектная перемен-

ная objC класса C. Причем последней в качестве значения присваивается

ссылка на новосозданный объект класса C. И пока все банально. Неба-

нально становится, когда мы командами objA=objC и objB=objC ссылку на

объект класса C присваиваем объектным переменным objA и objB. После

этого все три переменные (objA, objB и objC) ссылаются на один и тот же

объект.

О том, что переменная базового класса может ссылаться на объект

производного класса, мы уже намекали ранее. В этом смысле присваи-

вание переменной класса B ссылки на объект класса С не является

неожиданностью. Но, поскольку класс B является производным от

класса A, то на объект класса C может ссылаться и переменная класса

A. Имеет место своеобразная транзитивность. При этом ограничение

остается прежним: доступ через объектную переменную есть только

к  тем  членам,  которые  прописаны  в  классе,  к  которому  относится

объектная переменная.

Однако полномочия у переменных objA, objB и objC разные. Переменная

objC имеет доступ ко всем трем полям и методам. Переменная objB имеет

доступ к двум полям и двум методам: тем, что описаны в классе B и унасле-

дованы в классе B из класса A. Через переменную objA доступны только те

поля и методы, которые описаны непосредственно в классе A.

Для разнообразия мы вместо метода Console.ReadLine() в главном

методе  программы  использовали  метод  Consile.ReadKey().  Метод

Console.ReadLine()  считывает  текст  ввода  в  консоли,  а  признаком

окончания  ввода  является  нажатие  клавиши  Enter.  Метод  Consile.

ReadKey() считывает нажатую клавишу. Поэтому в рассматриваемом

примере консольное окно не закроется, пока мы не нажмем какую-

нибудь клавишу. Если бы мы использовали метод Console.ReadLine(), пришлось бы нажимать именно клавишу Enter.

Командами objB.nameA="красный" и objB.nameB="желтый" через перемен-

ную objB заполняем поля объекта objC. Третье поле, nameC, через пере-

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

пользуем команду objC.nameC="зеленый". Но перед этим командами objB.

showA() и objB.showB() проверяем поля, у которых есть значения. К тре-

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

заполнено и третье поле, проверяем результат присваивания значения

Замещение членов класса и переопределение методов           85

полям с помощью команды objC.showC(). Если же мы хотим получить до-

ступ к объекту класса C через переменную класса A, то доступными будут

лишь поле nameA и метод showA() объекта класса C. Эту ситуацию иллю-

стрируют команды objA.nameA="белый" и objA.showA(). Результат выполне-

ния программы пред ставлен на рис. 2.5.

Рис. 2.5.  Объектные переменные и наследование: результат выполнения программы

Как мы увидим далее в книге, не только объектные переменные базового

класса имеют честь ссылаться на объекты производных классов. В C# есть

интерфейсы, которые могут быть реализованы в классе. Переменные ин-

терфейсного типа могут ссылаться на объекты классов, в которых реали-

зуется соответствующий интерфейс. Ситуация во многом схожа с объект-

ными переменными базовых типов. Вместе с тем имеются и существенные

различия, но их обсуждать сейчас не время.

Замещение членов класса

и переопределение методов

— Так что же, выходит, у вас два мужа?

— Выходит, два.

— И оба Бунши?

— Оба!

Из к/ф «Иван Васильевич меняет профессию»

С наследованием связано еще два выдающихся феномена — замещение

членов и переопределение виртуальных методов. В некотором смысле они

идеологически близки, поскольку в обоих случаях речь идет о том, что

имеет место конфликт (в хорошем смысле этого слова) между унаследо-

ванным из базового класса членом и аналогичным членом, описываемым

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

при наследовании в производном классе описывается член с абсолютно

такими же параметрами, как и в базовом классе. Это может быть как поле, так и метод.

86

Глава 2. Классы и объекты

ПРИМЕЧАНИЕ Строго говоря, полями и методами члены класса не ограничиваются.

Членами класса могут быть, например, свойства или индексаторы —

Перейти на страницу:

Похожие книги