|
Программирование >> Обработка исключительных ситуаций
Можно этого не делать, но тогда компилятор выдаст предупреждение. Предупреждение (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). То, что в этой переменной в разные
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |