Правила хорошего тона в области ООП диктуют: каждый объект какого-либо реального (не абстрактного) класса из иерархии классов должен уметь сообщать свое имя. Зададим это правило в абстрактном классе Man с помощью абстрактного метода, который будет иметь осязаемое тело лишь в производных классах. Он будет возвращать строку текста с именем класса. Пусть наш абстрактный метод называется:
public abstract string Class(); // Этот метод обязаны реализовать не абстрактные потомки
В классе Man этого описания достаточно, но в производных классах Stud и Prof оно должно быть быть развернуто так, чтобы компилятор понял, что от него требуется. Аналогом абстрактного метода в C# является чисто виртуальная функция в С++. Описатель abstract заключает в себе смысл описателя virtual. Поэтому метод Class в производных классах должен иметь описатель override. Он используется для описания конкретных версий (продолжений) любых виртуальных функций. Например, в классе Stud.
public class Stud : Man // Класс, производный от класса Man
{
protected int course; // Данные
public int Course // Создайте свойство
{
// Используйте Helper.MakeInt
}
public Stud() : base() { course = 0; }
public override string Class() { return "Stud: "; }
// public override void In()
// public override string ToString()
// public override void Read (string[] tokens)
}
Имя класса можно узнать и с помощью Reflection, но нам нужен простой абстракный метод для иллюстрации понятия abstract. Обратите внимание на то, что, в отличие от С++, при объявлении производного класса указывается лишь имя базового класса и не указывается тип наследования. Команда разработчиков языка С# посчитала, что все типы наследования, кроме public, не нужны. Их нет в языке и поэтому в строке объявления производного класса отсутствует описатель типа наследования. Оба производных класса (Stud и Prof) должны иметь свои версии всех виртуальных функций, в том числе и абстрактной функции Class.
Для закрепления знаний по теме статические данные я предлагаю вам самостоятельно ввести в класс Man следующие данные, общие для всех объектов из иерархии Man:
· static int maxName = 25; — максимальная длина текста для поля name,
· static int maxAge = 150; — максимальное значение для поля age,
Для того, чтобы пользователь мог управлять закрытыми данными, целесообразно ввести в класс статические и обычные свойства (properties). Статические — для управления статическими данными, а обычные — обычными. Для приобретения навыка в использовании свойств попробуйте добавить в класс Man новые свойства. Мы уже показывали как это делается, когда вводили свойство для управления режимом сортировки коллекции. Используйте аналогичную технику для создания следующих свойств:
· public string Name — для чтения (get) и записи (set) поля name,
· public uint Age — для чтения (get) и записи (set) поля age,
· public static int MaxName — для чтения (get) и записи (set) поля maxName,
· public static int MaxAge — для чтения (get) и записи (set) поля maxAge,
Каждый уважающий себя класс должен иметь в своем составе конструктор копирования. Поэтому, в дополнение к двум имеющимся конструкторам класса Man добавьте еще один, который принимает в качестве параметра объект собственного класса и копирует все его данные в свои поля. Не забывайте про производные классы.
Теперь надо решить, какие методы класса Man следует сделать не абстрактыми, но виртуальными, то есть общими для всей иерархии и имеющими свои собственные версии способа выполнения в каждом из производных классов. В данный момент Man содержит лишь один метод, который стоит объявить виртуальным. Это метод:
public virtual void In() // Тело метода оставьте без изменений
Производные классы должны переопределить его, для того, чтобы добавить свою функциональность. Например, в классе Stud он может иметь такую реализацию:
public override void In()
{
Console.Write (Class());
base.In(); // Вызов родительской версии
course = Helper.AskInt ("Course: ", 0, 6);
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.