📚 Hub Books: Онлайн-чтение книгРазная литератураИнтернет-журнал "Домашняя лаборатория", 2007 №9 - Журнал «Домашняя лаборатория»

Интернет-журнал "Домашняя лаборатория", 2007 №9 - Журнал «Домашняя лаборатория»

Шрифт:

-
+

Интервал:

-
+
1 ... 346 347 348 349 350 351 352 353 354 ... 415
Перейти на страницу:
могут делать методы класса, создавая объекты для собственных нужд со специальной инициализацией. Пример такого конструктора будет дан позже.

В классе можно объявить статический конструктор с атрибутом static. Он вызывается автоматически — его не нужно вызывать стандартным образом. Точный момент вызова не определен, но гарантируется, что вызов произойдет до создания первого объекта класса. Такой конструктор может выполнять некоторую предварительную работу, которую нужно выполнить один раз, например, связаться с базой данных, заполнить значения статических полей класса, создать константы класса, выполнить другие подобные действия. Статический конструктор, вызываемый автоматически, не должен иметь модификаторов доступа. Вот пример объявления такого конструктора в классе Person;

static Person()

{

      Console.WriteLine("Выполняется статический конструктор!");

}

В нашей тестирующей процедуре, работающей с объектами класса Person, этот конструктор вызывается первым, и первым появляется сообщение этого конструктора.

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

Деструкторы класса

Если задача создания объектов полностью возлагается на программиста, то задача удаления объектов, после того, как они стали не нужными, в Visual Studio.Net снята с программиста и возложена на соответствующий инструментарий — сборщик мусора. В классическом варианте языка C++ деструктор так же необходим классу, как и конструктор. В языке C# у класса может быть деструктор, но он не занимается удалением объектов и не вызывается нормальным образом в ходе выполнения программы. Так же, как и статический конструктор, деструктор класса, если он есть, вызывается автоматически в процессе сборки мусора. Его роль — в освобождении ресурсов, например, файлов, открытых объектом. Деструктор C# фактически является финализатором (finalizer), с которыми мы еще встретимся при обсуждении исключительных ситуаций. Приведу формальное описание деструктора класса Person;

— Person()

{

      //Код деструктора

}

Имя деструктора строится из имени класса с предшествующим ему символом ~ (тильда). Как и у статического конструктора, у деструктора не указывается модификатор доступа.

Проектирование класса Rational

В заключение этой лекции займемся проектированием класса Rational, описывающего известный в математике тип данных — рациональные числа. По ходу проектирования будут вводиться новые детали, связанные с описанием класса. Начнем проектирование, как обычно, с задания тега <summary>, описывающего назначение класса, его свойства и поведение. Вот этот текст:

/// <summary>

/// Класс Rational

/// определяет новый тип данных — рациональные числа и

/// основные операции над ними — сложение, умножение,

/// вычитание и деление. Рациональное число задается парой

/// целых чисел (m, n) и изображается обычно в виде дроби m/n.

/// Число m называется числителем, n — знаменателем. Для

/// каждого рационального числа существует множество его

/// представлений, например, 1/2, 2/4, 3/6, 6/12 — задают

/// одно и тоже рациональное число. Среди всех представлений

/// можно выделить то, в котором числитель и знаменатель

/// взаимно несократимы. Такой представитель будет храниться

/// в полях класса. Операции над рациональными числами

/// определяются естественным для математики образом

/// </summary>

public class Rational

{

       // Описание тела класса Rational

}//Rational

Свойства класса Rational

Два целых числа — m и n тип представляют рациональное число. Они и становятся полями класса. Совершенно естественно сделать эти поля закрытыми. Разумная стратегия доступа к ним — "ни чтения, ни записи", поскольку пользователь не должен знать, как представлено рациональное число в классе, и не должен иметь доступа к составляющим рационального числа. Поэтому для таких закрытых полей не будут определяться методы-свойства. Вот объявление полей класса:

//Поля класса. Числитель и знаменатель рационального числа,

int m,n;

Конструкторы класса Rational

Инициализация полей конструктором по умолчанию никак не может нас устраивать, поскольку нулевой знаменатель — это нонсенс. Поэтому определим конструктор с аргументами, которому будут передаваться два целых: числитель и знаменатель создаваемого числа. Кажется, что это единственный разумный конструктор, который может понадобиться нашему классу. Однако чуть позже мы добавим в класс закрытый конструктор и статический конструктор, позволяющий создать константы нашего класса. Вот определение конструктора'.

/// <summary>

/// Конструктор класса. Создает рациональное число

/// m/n, эквивалентное a/b, но со взаимно несократимыми

/// числителем и знаменателем. Если Ь=0, то результатом

/// является рациональное число 0 — пара (0,1).

/// </summary>

/// <param name="а">числитель</раrаm>

/// <param name="Ь">знаменатель</раrаm>

public Rational(int a, int b)

{

      if (b==0) {m=0; n=1;}

      else

      {

           // приведение знака if(b<0) {b=-b; a=-a;}

           // приведение к несократимой дроби

           int d = nod(a,b);

           m=a/d; n=b/d;

       }

}

Как видите, конструктор класса может быть довольно сложным.

В нем, как в нашем случае, может проверяться корректность задаваемых аргументов. Для рациональных чисел мы полагаем, что задание нулевого знаменателя означает задание рационального числа о, и это эквивалентно заданию пары (0, 1). В остальных случаях выполняется приведение заданной пары чисел к эквивалентному рациональному числу с несократимыми числителем и знаменателем. По ходу дела вызывается закрытый метод класса, вычисляющий значение НОД (а, Ь) — наибольшего общего делителя чисел а и b .

Методы класса Rational

Если поля класса почти всегда закрываются, чтобы скрыть от пользователя представление данных класса, то методы класса всегда имеют открытую часть — те сервисы (службы), которые класс предоставляет своим клиентам и наследникам. Но не все методы открываются. Большая часть методов класса может быть закрытой, скрывая от клиентов детали реализации, необходимые для внутреннего использования. Заметьте, сокрытие представления и реализации делается не по соображениям утаивания того, как реализована система. Чаще всего, ничто не мешает клиентам ознакомиться с полным текстом класса. Сокрытие делается в интересах самих клиентов. При сопровождении программной системы изменения в ней неизбежны. Клиенты не почувствуют на себе негативные последствия изменений, если они делаются в закрытой части класса. Чем больше закрытая часть класса, тем меньше влияние изменений на клиентов класса.

Закрытый метод НОД

Метод, вычисляющий наибольший общий делитель пары чисел, понадобится не только конструктору класса, но и всем операциям над рациональными числами. Алгоритм нахождения общего делителя хорошо известен со времен Эвклида. Я приведу программный код метода без особых пояснений:

/// <summary>

/// Закрытый метод класса.

/// Возвращает наибольший общий делитель чисел а, Ь

/// </summary>

/// <param name="а">первое число</param>

/// <param name="Ь">второе число, положительное</param>

/// <returns>HOД(a,b)</returns>

int nod(int m, int n)

{

1 ... 346 347 348 349 350 351 352 353 354 ... 415
Перейти на страницу:

Комментарии

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

Никто еще не прокомментировал. Хотите быть первым, кто выскажется?