Программирование >>  Обработка исключительных ситуаций 

1 ... 57 58 59 [ 60 ] 61 62 63 ... 142


Можно этого не делать, но тогда компилятор выдаст предупреждение. Предупреждение (warning) - это не ошибка, оно не препятствует успешной компиляции, но тем не менее...

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

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

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

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

Метод Passport класса Daemon замещает соответствующий метод базового класса, однако возможность доступа к методу базового класса из метода производного класса сохраняется. Для этого перед вызовом метода указывается все то же волшебное слово base, например:

case.PassportO:

СОВЕТ-

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

Вот, например, как выглядел бы метод Passport, если бы мы в классе Daemon хотели не полностью переопределить поведение его предка, а дополнить его:

*e v public void PassportO base.PassportO;

Console.WriteLineC brain = {1} , brain );



Во время выполнения программы объекты хранятся в отдельных переменных, массивах или других коллекциях . Во многих случаях удобно оперировать объектами одной иерархии единообразно, то есть использовать один и тот же программный код для работы с экземплярами разных классов. Желательно иметь возможность описать:

объект, в который во время выполнения программы заносятся ссылки на объекты разных классов иерархии;

контейнер, в котором хранятся объекты разных классов, относящиеся к одной иерархии;

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

метод, из которого в зависимости от типа вызвавшего его объекта вызываются соответствующие методы.

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

Давайте попробуем описать массив объектов базового класса и занести туда объекты производного класса. В листинге 8.2 в массиве типа Monster хранятся два объекта типа Monster и один - типа Daemon.

Листинг 8.2. Массив объектов разных типов using System;

namespace .ConsoleApplicationl

class Monster

class Daemon : Monster

1 Коллекция - объект, предназначенный для хранения данных и предоставляющий методы доступа к ним. Например, массив предоставляет прямой доступ к любому его элементу по индексу. Коллекции библиотеки .NET рассматриваются в главе 13.

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

Элементы базового класса, определенные как private, в производном классе недоступны. Поэтому в методе Passport для доступа к полям name, health и ammo пришлось использовать соответствующие свойства базового класса. Другое решение заключается в том, чтобы определить эти поля со спецификатором protected, в этом случае они будут доступны методам всех классов, производных от Monster. Оба решения имеют свои достоинства и недостатки.

ВНИМАНИ Е-

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



... см. листинг 8.1

class Classl { static void MainO {

const int n = 3;

Monster[] stado = new Monsterln];

stado[0] = new Monster( Monia ); stado[l] = new Monster( Monk ); stado[2] = new Daemon ( Dimon , 3 );

foreach ( Monster elem in stado ) elem.PassportO; 1

for (int i = 0; i < n; ++i ) stado[i].Ammo = 0; 111

Console.WriteLineC);

foreach ( Monster elem in stado ) el em. PassportO; 3

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

Monster Monia health = 100 am = 100

Monster Monk health = 100 ammo = 100 Monster Dimon health - 100 ammo = 100

Monster Monia health = 100 ammo = 0 Monster Monk health = 100 ammo = 0

Monster Dimon health = 100 ammo = 0

Результат радует нас только частично: объект типа Daemon действительно можно поместить в массив, состоящий из элементов типа Monster, но для него вызываются только методы и свойства, унаследованные от предка. Это устраивает нас в операторе 2, а в операторах 1 и 3 хотелось бы, чтобы вызывался метод Passport, переопределенный в потомке.

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

Это и понятно: ведь компилятор должен еще до выполнения программы решить, какой метод вызывать, и вставить в код фрагмент, передающий управление на этот метод (этот процесс называется ранним связыванием). При этом компилятор может руководствоваться только типом переменной, для которой вызывается метод или свойство (например, stadoli ] .Ammo). То, что в этой переменной в разные



1 ... 57 58 59 [ 60 ] 61 62 63 ... 142

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика