Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие СS_Шульга.doc
Скачиваний:
48
Добавлен:
12.02.2015
Размер:
703.49 Кб
Скачать

Глава 8. Наследование

Наследование – это возможность создания иерархии классов, в которой потомки (производные классы, наследники) получают элементов своих предков (родителей, базовых классов), могут их изменять и добавлять новые.

Класс в C# может иметь произвольное количество потомков и только одного предка. При описании класса имя его предка записывается в заголовке класса после двоеточия. Если имя предка не указано, предком считается базовый класс всей иерархии System.Object:

[ атрибуты ] [ спецификаторы ] class имя_класса [ : предки ]

тело класса

Обратите внимание, что слово "предки" присутствует в описании класса во множественном числе, хотя класс может иметь только одного предка. Причина в том, что класс наряду с единственным предком может наследовать от интерфейсов — специального вида классов, не имеющих реализации, которые будут рассмотрены в следующих лекциях.

Например, создадим производный класс CStudentMasterот базового классаCStudent, предназначенный для храненияданных о студенте магиструры.

class CStudentMaster: CStudent

{

string research;

public CStudentMaster()

{

research = "Unknown";

}

public CStudentMaster(string name, string speciality, gender_type gender, int year_tr, string research):base(name, speciality, gender, year_tr)

{

Year=year_tr;

this.research=research;

}

public string Research

{

get { return research; }

set

{

if (research == "Unknown")

{

if (value == "") name = "Unknown";

else research = value;

}

}

}

new public int Year

{

get { return year_tr; }

set

{ // способ установки свойства

if (value >= 1 && value <= 2)

{

year_tr = value;

}

else throw new Exception("При изменении курса студента указано недопустимое значение. Значение должно быть интевале [1,2]");

}

}

new public void input()

{

base.input();

Year = year_tr;

Console.WriteLine("Введите тему НИР студента");

Research = Console.ReadLine();

}

new public void output()

{

base.output();

Console.WriteLine("research ={0,10}", research);

}

}

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

Все поля и методы базового класса, кроме конструкторов, наследуются.

Если поля или методы класса – предка имеют тип private, то класс-потомок не имеет к ним прямого доступа и для работы с ними в необходимо использовать открытые методы базового класса.

Если функциям производного класса требуется работать с полями базового, то в базовом классе такие поля можно описать как protected. Поэтому если проектируется иерархия классов, то это более предпочтительный вариант. Таким образом, целесообразно изменить видимость полей в классеCStudentcprivateна protected.

В производном классе могут быть собственные поля и методы.

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

В производном классе можно описать поле с таким же именем, что и в базовом классе, возможно, изменив тип этого поля и его модификаторы. В этом случае поле базового класса будет скрыто (не удалено!). Скрытое родительское поле остается доступно в классе-наследнике через обращение base.имя_поля.

В классе CStudentMasterдобавлено одно полеresearchи одно свойство Research.

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

Переопределяемый метод отличается списком параметров. Вызов нужного метода определяется обычными правилами перегрузки методов.

Переопределение метода с модификаторами virtual, abstract или override. Это наиболее интересная ситуация, и она будет подробно рассмотрена далее. При переопределении сохраняется заголовок и модификаторы доступа наследуемого метода.

Скрытие метода, т.е. его переопределение с таким же заголовком с модификатором new. Здесь ситуация такая же, как и со скрытием полей. При вызове метода по его имени предпочтение будет отдаваться методу потомка. Это не означает, что метод родителя становится недоступным. В переопределенном методе производного класса вызвать метод базового класса можно обратившись к нему с помощью ключевого слова base, например base.output();В классе CStudentMaster переопределены скрытием методы input(), output(), свойство Year;

Таким образом, переопределение методов реализует принцип полиморфизма.

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

Правила наследования конструкторов класса

  1. Конструкторы класса не наследуются. Следовательно, производный класс должен иметь собственные конструкторы.

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

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

  4. В случае необходимости явного вызова конструктора базового класса из конструктора производного класса конструктор производного класса определяют следующим образом имя_производного_класса (список формальных параметров): base(список фактических параметров) {тело}

  5. В случае иерархии классов, конструкторы базовых классов вызываются, начиная с самого верхнего уровня.

Для проверки работы класса можно использовать следующий код.

Console.WriteLine("Для демонстрации методов класса создайте студента магистратуры");

CStudentMaster s = new CStudentMaster();

Console.WriteLine("\nСоздан студент:");

s.output();

Console.WriteLine("\nИзмените данные о студенте:");

s.input();

Console.WriteLine("\nДанные о студенте изменены:");

s.output();

CStudentMaster s1 = new CStudentMaster("Петрова", "Информатика", gender_type.female, 1, "Automata");

Console.WriteLine("\nСоздан новый студент:");

s1.output();