Разработка приложений на языке C#. Полезные настройки. Особые спецификаторы формата, страница 30

Правила хорошего тона в области ООП диктуют: каждый объект какого-либо реального (не абстрактного) класса из иерархии классов должен уметь сообщать свое имя. Зададим это правило в абстрактном классе 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);