На этом шаге мы рассмотрим простейший пример, иллюстрирующий основные идеи наследования.
Идея наследования достаточно проста: вместо того чтобы создавать новый класс, так сказать, "на пустом месте", мы можем создать его на основе уже существующего класса. Класс, который используется как основа для создания нового класса, называется базовым. Класс, который создается на основе базового класса, называется производным. Главный (но далеко не единственный) эффект от создания производного класса на основе базового состоит в том, что открытые (и защищенные) члены из базового класса автоматически добавляются (то есть наследуются) в производный класс.
Технически наследование реализуется достаточно просто. Базовый класс каким-либо особым образом описывать не нужно. Это самый обычный класс. В описании производного класса после названия класса через двоеточие указывается название базового класса. Так, если мы описываем класс MyClass и хотим, чтобы он был производным от уже существующего класса Base, то шаблон для описания класса MyClass будет выглядеть следующим образом:
class MyClass: Base { // Код производного класса }
В теле класса MyClass описываются только те члены, которые "добавляются" в дополнение к членам, наследуемым из класса Base. Повторно описывать члены класса Base в классе MyClass не нужно. При этом мы можем обращаться к унаследованным членам, хотя формально они в классе MyClass не описаны.
Также стоит заметить, что у производного класса может быть только один базовый класс: нельзя создать производный класс на основе сразу нескольких базовых классов. Вместе с тем производный класс сам может быть базовым классом для другого класса. Проще говоря, мы можем реализовать цепочку наследования: на основе базового класса создается производный класс, а на его основе создается еще один производный класс и так далее. Понятно, что один и тот же класс может быть базовым сразу для нескольких производных классов.
Небольшой пример, в котором используется наследование классов, представлен в примере ниже.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace pr139_1 { // Базовый класс: class Base { // Открытое целочисленное поле: public int code; // Открытый метод: public void show() { // Отображение значения поля: Console.WriteLine("Поле code: " + code); } } // Производный класс: class MyClass: Base { // Открытое символьное поле: public char symb; // Открытый метод: public void display() { // Отображение значения символьного поля: Console.WriteLine("Поле symb: " + symb); // Вызов унаследованного метода: show(); } // Открытое свойство: public int number { // Аксессор для считывания значения: get { // Обращение к унаследованному полю: return code; } // Аксессор для присваивания значения: set { // Обращение к унаследованному полю: code = value; } } } // Класс с главным методом: class Program { static void Main() { // Создание объекта производного класса: MyClass obj = new MyClass(); // Присваивание значений полям: obj.code = 100; obj.symb = 'A'; // Вызов метода: obj.display(); // Использование свойства: obj.number = 200; Console.WriteLine("Свойство number: " + obj.number); // Вызов метода: obj.show(); // Задержка: Console.ReadLine(); } } }
Результат выполнения программы такой.
Рис.1. Результат выполнения программы
Пример очень простой. Мы описали базовый класс Base, в котором есть целочисленное поле code и метод show() без аргументов, не возвращающий результат. При вызове метода в консольном окне отображается значение числового поля объекта, из которого вызывается метод.
На основе класса Base путем наследования создается класс MyClass. Непосредственно в этом классе описано символьное поле symb, метод display() и целочисленное свойство number. При этом в программном коде класса MyClass мы использовали обращение к полю code и методу show(), хотя непосредственно в теле класса они не описывались. Эго стало возможным благодаря тому, что поле code и метод show() наследуются из класса Base. Поэтому в классе MyClass они присутствуют, и мы их можем использовать так, как если бы они были описаны в классе MyClass.
Если более детально, то при вызове метода display() сначала отображается значение символьного поля объекта, после чего вызывается метод show(). Метод show(), в соответствии с тем, как он описан в классе Base, отображает в консольном окне значение целочисленного поля объекта, из которого метод вызывается (а вызывается он в данном случае из объекта производного класса).
Свойство number в производном классе непосредственно связано с полем code, которое наследуется из базового класса. При считывании значения свойства number возвращается значение поля code, а при присваивании значения свойству number значение фактически присваивается полю code.
В главном методе программы командой
MyClass obj = new MyClass();
obj.code = 100;
obj.symb = 'A';
obj.display();
Командой
obj.number = 200;
Console.WriteLine("Свойство number: " + obj.number);
obj.show(); ,
На следующем шаге мы рассмотрим наследование и уровни доступа.