
- •Классы и структуры в c#. Класс Object, его методы.
- •Объявление и вызов методов класса.
- •Вызов методов:
- •Конструктор и деструктор класса.
- •Отношение наследования, объявление класса-потомка.
- •Создание экземпляров класса-потомка, взаимодействие конструкторов родителя и потомка.
- •Три способа изменения методов класса-родителя в классе-потомке.
- •Статическое и динамическое связывание
- •Полиморфизм. Три механизма реализации полиморфизма.
- •16. Абстрактные классы. Абстрактные классы
- •17. Интерфейсы, объявления интерфейсов.
- •18. Члены интерфейсов.
- •Реализация интерфейсов
Отношение наследования, объявление класса-потомка.
Для отношения наследования используется терминология, заимствованная из естественного языка. Прямые классы-наследники часто называются сыновними или дочерними классами. Непрямые родители называются предками, а их непрямые наследники - потомками.
Мощь ООП основана на наследовании. Когда построен полезный класс, то он может многократно использоваться. Повторное использование - это одна из главных целей ООП. Но и для хороших классов неизбежно наступает момент, когда необходимо расширить возможности класса, придать ему новую функциональность, изменить интерфейс. Всякая попытка изменять сам работающий класс чревата большими неприятностями - могут перестать работать прекрасно работавшие программы, многим клиентам класса вовсе не нужен новый интерфейс и новые возможности. Здесь-то и приходит на выручку наследование. Существующий класс не меняется, но создается его потомок, продолжающий дело отца, только уже на новом уровне.
Класс- потомок наследует все возможности родительского класса - все поля и все методы, открытую и закрытую часть класса. Правда, не ко всем полям и методам класса возможен прямой доступ потомка. Поля и методы родительского класса, снабженные атрибутом private, хотя и наследуются, но по-прежнему остаются закрытыми, и методы, создаваемыепотомком, не могут к ним обращаться напрямую, а только через методы, наследованные от родителя. Единственное, что не наследует потомок - это конструкторы родительского класса. Конструкторы потомок должен создавать сам. В этом есть некоторая разумная идея, и я позже поясню ее суть.
Создание экземпляров класса-потомка, взаимодействие конструкторов родителя и потомка.
Ничего не делающий самостоятельно потомок не эффективен, от него мало проку. Что же может делать потомок? Прежде всего, он может добавить новые свойства - поля класса. Заметьте, потомок не может ни отменить, ни изменить модификаторы или типы полей, наследованных от родителя - он может только добавить собственные поля.
Каждый класс должен позаботиться о создании собственных конструкторов. Он не может в этом вопросе полагаться на родителя, поскольку, как правило, добавляет собственные поля, о которых родитель ничего не может знать. Конечно, если не задать конструкторов класса, то будет добавлен конструктор по умолчанию, инициализирующий все поля значениями по умолчанию, как это мы видели в предыдущем примере. Но это редкая ситуация. Чаще всего, класс создает собственные конструкторы и, как правило, не один, задавая разные варианты инициализации полей.
При создании конструкторов классов потомков есть одна важная особенность. Всякий конструктор создает объект класса - структуру, содержащую поля класса. Но потомок, прежде чем создать собственный объект, вызывает конструктор родителя, создавая родительский объект, который затем будет дополнен полями потомка. Ввиду транзитивности этого процесса, конструктор родителя вызывает конструктор своего родителя, и этот процесс продолжается, пока первым делом не будет создан объект прародителя.
Вызов конструктора родителя происходит не в теле конструктора, а в заголовке, пока еще не создан объект класса. Для вызова конструктора используется ключевое слово base, именующее родительский класс.
Для конструктора без аргументов вызов аналогичного конструктора родителя подразумевается по умолчанию. Для конструкторов с аргументами вызов конструктора с аргументами родительского класса должен быть явным. Этот вызов синтаксически следует сразу за списком аргументов конструктора, будучи отделен от этого списка символом двоеточия. Конструктору потомка передаются все аргументы, необходимые для инициализации полей, часть из которых передаются конструктору родителя для инициализации родительских полей.
Итак, вызов конструктора - потомка приводит к цепочке вызовов конструкторов - предков, заканчивающейся вызовом конструктора прародителя. Затем в обратном порядке создаются объекты, начиная с объекта прародителя, и выполняются тела соответствующих конструкторов, инициализирующие поля и выполняющие другую работу этих конструкторов. Последним создается объект потомка и выполняется тело конструктора потомка.