netlib.narod.ru | < Назад | Оглавление | Далее > |
Вполне возможно, что по прошествии некоторого времени пользования классом вы подумаете: «Этот класс очень хорош, но лучше, если б...» Если у вас есть исходный код класса, можете просто открыть его в редакторе, добавить новый метод, перекомпилировать и начать использовать. Но у вас может и не быть исходного кода. Возможно, что вам доступна только скомпилированная версия класса в виде DLL.
Может случиться и так: вы хотите, чтобы некоторые функции класса выполнялись иначе. Но класс уже используется в существующем виде другими приложениями и вполне их устраивает. Изменения требуются только для одного нового приложения, и вы предпочли бы не «засорять» код исходной версии.
В объектно-ориентированных языках, подобных С#, реализована возможность наследования (inheritance). Можно определить новый класс, основанный на существующем классе. Говорят, что вы наследуете (inherit) класс от существующего класса или создаете подкласс (subclass) существующего класса. В новом классе должны содержаться только новые данные и код. Все классы С# и .NET Framework являются наследниками класса Object или классов-наследников Object. Говорят также, что все классы в конечном счете являются производными от Object.
Давайте создадим новый класс DatePlus, унаследованный от Date. DatePlus будет обладать новым свойством DaysSincel600. Благодаря наличию этого свойства можно сделать, чтобы DatePlus вычислял разницу в днях между двумя датами.
Вот программа, в которой определен класс DatePlus.
CsDateConstructors.cs
//---------------------------------------------------- // CsDateInheritance.cs (C) 2001 by Charles Petzold //---------------------------------------------------- using System; class CsDateInheritance { public static void Main() { DatePlus birth = new DatePlus(1953, 2, 2); DatePlus today = new DatePlus(2001, 8, 29); Console.WriteLine("Birthday = {0}", birth); Console.WriteLine("Today = " + today); Console.WriteLine("Days since birthday = {0}", today - birth); } } class DatePlus:Date { public DatePlus() {} public DatePlus(int year, int month, int day):base(year, month, day) {} public int DaySince1600 { get { return 365 - (Year - 1606) + (Year - 1597) / 4 - (Year - 1601) / 100 + (Year - 1601) / 400 + DayOfYear; } } public override string ToString() { string[] str = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } return String.Format("{0} {1} {2}", Day, str[Month - 1], Year); } public static int operator - (DatePlus date1, DatePlus date2) { return date1.DaysSince1600 - date2.DaysSince1600; } }
Эту программу необходимо компилировать вместе с файлом CsDateConstructors.cs — самой последней реализацией класса Date. Так как имеется два класса, содержащих метод Main, нужно указать компилятору, какой из классов, содержащих метод Main, использовать для входа в программу.
При компиляции в командной строке надо ввести:
csc CsDateConstructors.cs CsDateInheritance.cs /main:CsDateInheritance
При этом нужно быть внимательным к регистру букв. Имена файлов можно вводить в любом регистре, но параметр /main обращается к классу, и регистр символов этого параметра должен соответствовать имени класса, определенному в файле. В случае Visual С# .NET нужно добавить CsDateConstructors.cs в проект CsDateInheritance. Для этого выберите в меню Project | Add Existing Item. При выборе файла CsDateConstructors.cs в диалоговом окне Add Existing Item щелкните по стрелке рядом с кнопкой Open и выберите Link File. Этот параметр позволяет избежать создания копии файла CsDateConstructors.cs, а также проблем, возникающих в случае, когда версия одной из копий этого файла изменилась, а другую при этом забыли обновить.
Обратите внимание на первую строку определения класса DatePlus:
class DatePlus:Date
Это означает, что DatePlus наследуется от Date. Классу DatePlus не нужно выполнять в конструкторах специальных действий. Поэтому для него определен конструктор по умолчанию с пустым телом:
public DatePlus() {}
При создании экземпляра класса вызываются конструкторы по умолчанию всех объектов, от которых унаследован класс, начиная с конструктора по умолчанию класса Object и кончая конструктором по умолчанию класса объекта, который вы создаете.
Это правило неприменимо к конструкторам не по умолчанию. Конструктор с тремя параметрами не выполняет никаких специальных действий в DatePlus, но нужно определить его в классе и явно вызвать конструктор базового (base) класса, от которого наследуется DatePlus, — класса Date. Определение конструктора не по умолчанию имеет такой синтаксис:
public DatePlus(int year, int month, int day):base(year, month, day) {}
Так как конструктор не делает в классе DatePlus ничего специфического, его тело пусто.
В классе DatePlus, кроме свойства DaysSincel600, реализованы две изящные возможности. Во-первых, в DatePlus определен оператор вычитания (–) для объектов этого класса. Это называется перегрузкой (overloading) оператора. Обычно оператор вычитания определяется только для чисел, но здесь он хорошо подходит и для работы с датами. Тело этого перегруженного оператора довольно простое: в нем просто вычитаются DaysSincel600 двух дат.
Например, если определить два объекта DatePlus:
DatePlus birth = new DatePlus(1953, 2, 2); DatePlus today = new DatePlus(2001, 8, 29);
то можно посчитать разницу в днях между этими датами при помощи выражения
today - birth
Заметьте: я не реализовал в этом классе перегруженный оператор сложения. Не имеет смысла складывать друг с другом две даты. Однако, я мог бы реализовать сложение даты и числа, результатом которого является новая дата. Но тогда потребовалось бы писать код, чтобы преобразовать новое значение DaysSincel600 в дату. Зато довольно легко реализовать операторы сравнения (<, >, <= и >=).
Во-вторых, я уже упоминал, что все объекты в конечном счете наследуются от Object. В классе Object реализован метод ToString, предназначенный для преобразования объекта в читабельную текстовую строку. Мы уже использовали ToString. При конкатенации числовой переменной с текстовой строкой автоматически вызывается метод ToString этой переменной. При передаче объекта в метод ConsoleWriteLine также вызывается метод ToString объекта.
Но по умолчанию метод ToString класса Object возвращает имя класса, например строку «DatePlus». Ничего страшного: ведь любой класс, происходящий от Object (т.е. любой класс С#) может переопределить (override) метод ToString класса Object своим собственным. В классе DatePlus реализован собственный метод ToString, использующий статический метод String.Format для преобразования даты в текстовую строку. Стало возможным вызвать метод Console.WriteLine, указав в качестве параметра объект DatePlus, и показать форматированную дату. Вывод программы CsDateInheritance выглядит так
Birthday = 2 Feb 1953 Today = 29 Aug 2001 Days since birthday = 17740
Теперь мы готовы более подробно рассмотреть модификаторы доступа. Если поле, свойство или метод определены как private, они видимы и доступны только внутри класса. Если поле, свойство или метод определены как public, они видимы и доступны в других классах. Если поле, свойство или метод определены как protected, они видимы и доступны только внутри класса и любого класса, унаследованного от этого класса.
Метод ToString класса Object определен с модификатором virtual. Метод, определенный как virtual, может переопределяться наследниками класса. При переопределении метода используется модификатор override, показывающий, что метод заменяется собственной версией, реализованной в этом классе. Модификатор override необходим, чтобы нельзя было ошибиться, случайно переопределив виртуальный метод, когда этого не планировалось.
Кроме того, в классах можно переопределять методы, не объявленные как virtual. В этом случае новый метод должен содержать модификатор new.
Кроме ToString, класс Object содержит несколько других методов, в том числе GetType. GetType возвращает объект типа Туре. Туре — это класс, определенный в пространстве имен System, позволяющий получить информацию об объекте, в частности, о его методах, свойствах и полях. Оператор С# typeof также возвращает объект типа Туре. Отличие между ними в том, что GetType применяется к объекту, a typeof — к классу. В методе Main программы CsDataInheritance результатом выражения
today.GetType(} == typeof(DatePlus)
будет true.
netlib.narod.ru | < Назад | Оглавление | Далее > |