Чтение онлайн

на главную

Жанры

Интернет-журнал "Домашняя лаборатория", 2007 №9
Шрифт:

Рис. 16.5. Операции и выражения над рациональными числами

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

Рассмотрим важную проблему определения констант в собственном классе. Определим две константы 0 и 1 класса Rational. Кажется, что сделать это невозможно из-за ограничений, накладываемых на объявление констант. Напомню, константы должны быть инициализированы в момент объявления, и их значения должны быть

заданы константными выражениями, известными в момент компиляции. Но в момент компиляции у класса Rational нет никаких известных константных выражений. Как же быть? Справиться с проблемой поможет статический конструктор, созданный для решения подобных задач. Роль констант класса будут играть статические поля, объявленные с атрибутом readonly, то есть доступные только для чтения. Нам также будет полезен закрытый конструктор класса. Еще укажем, что введение констант класса требует использования экзотических средств языка С#. Вначале определим закрытый конструктор:

private Rational(int a, int b, string t)

{

m = a; n = b;

}

He забудем, что при перегрузке методов (в данном случае конструкторов) сигнатуры должны различаться, и поэтому пришлось ввести дополнительный аргумент t для избежания конфликтов. Поскольку конструктор закрытый, то гарантируется корректное задание аргументов при его вызове. Определим теперь константы класса, которые, как я уже говорил, задаются статическими полями с атрибутом readonly:

//Константы класса 0 и 1 — Zero и One

public static readonly Rational Zero, One;

А теперь зададим статический конструктор, в котором определяются значения констант:

static Rational

{

Console.WriteLine("static constructor Rational");

Zero = new Rational(0, 1, "private");

One = new Rational (1, 1, "private");

}//Статический конструктор

Как это все работает? Статический конструктор вызывается автоматически один раз до начала работы с объектами класса. Он и задаст значения статических полей Zero, One, представляющих рациональные числа с заданным значением. Поскольку эти поля имеют атрибут static и readonly, то они доступны для всех объектов класса и не изменяются в ходе вычислений, являясь настоящими константами класса. Прежде чем привести пример работы с константами, давайте добавим в наш класс важные булевы операции над рациональными числами — равенство и неравенство, больше и меньше. При этом две последние операции сделаем перегруженными, позволяя сравнивать рациональные числа с числами типа double:

public static bool operator ==(Rational r1, Rational r2)

}

return ((r1.m==r2.m) & & (r1.n==r2.n));

}

public static bool operator!=(Rational r1, Rational r2)

}

return ((r1.m! =r2.m) || (r1.n!=r2.n));

}

public static bool operator <(Rational r1, Rational r2)

}

return (r1.m*r2. n < r2.m* r1.n);

}

public static bool operator >(Rational r1, Rational r2)

}

return (r1.m * r2.n > r2.m* r1.n);

}

public static bool operator <(Rational rl, double r2)

{

return((double)r1.m / (double)rl.n < r2);

}

public static bool operator >(Rational rl, double r2)

{

return((double)r1.m / (double)r1.n > r2);

}

Наш последний пример демонстрирует работу с константами, булевыми и арифметическими выражениями над рациональными числами:

public void TestRationalConst

{

Rational r1 = new Rational(2,8), r2 =new Rational(2,5);

Rational r3 = new Rational(4, 10), r4 = new Rational(3,7);

Rational r5 = Rational.Zero, r6 = Rational.Zero;

if ((r1!= Rational.Zero) && (r2 == r3)) r5 =(r3+Rational.One)*r4;

r6 = Rational.One + Rational.One;

r1.PrintRational ("r1: (2,8)");

r2.PrintRational ("r2: (2,5)");

r3.PrintRational ("r3: (4,10)");

r4.PrintRational ("r4: (3,7)");

r5.PrintRational ("r5: ((r3 +1)*r4)");

r6.PrintRational ("r6: (1 + 1)");

}

Результаты

работы этого примера показаны на рис. 16.6.

Рис. 16.6. Константы и выражения типа Rational

17. Структуры и перечисления

Понятие развернутого и ссылочного типа. Структуры — реализация развернутых классов. Синтаксис структур. Сравнение структур и классов. Встроенные структуры. Перечисление — частный случай класса. Особенности перечислений. Примеры.

Развернутые и ссылочные типы

Рассмотрим объявление объекта класса T с инициализацией:

Т х = new Т;

Напомню, как выполняется этот оператор. В памяти создается объект типа T, основанного на классе T, и сущность х связывается с этим объектом. Сущность, не прошедшая инициализацию (явную или неявную), не связана ни с одним объектом, а потому не может использоваться в вычислениях — у нее нет полей, хранящих значения, она не может вызывать методы класса. Объектам нужна память, чтобы с ними можно было работать. Есть две классические стратегии выделения памяти и связывания объекта, создаваемого в памяти, и сущности, объявленной в тексте.

Определение 1. Класс T относится к развернутому типу, если память отводится сущности х; объект разворачивается на памяти, жестко связанной с сущностью.

Определение 2. Класс T относится к ссылочному типу, если память отводится объекту; сущность х является ссылкой на объект.

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

Развернутые и ссылочные типы порождают две различные семантики присваивания — развернутое присваивание и ссылочное присваивание. Рассмотрим присваивание:

у = х;

Когда сущность у и выражение х принадлежат развернутому типу, то при присваивании изменяется объект. Значения полей объекта, связанного с сущностью у, изменяются, получая значения полей объекта, связанного с х. Когда сущность у и выражение х принадлежат ссылочному типу, то изменяется ссылка, но не объект. Ссылка у получает значение ссылки х, и обе они после присваивания указывают на один и тот же объект.

Поделиться:
Популярные книги

Идеальный мир для Лекаря 20

Сапфир Олег
20. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 20

Пропала, или Как влюбить в себя жену

Юнина Наталья
2. Исцели меня
Любовные романы:
современные любовные романы
6.70
рейтинг книги
Пропала, или Как влюбить в себя жену

Снегурка для опера Морозова

Бигси Анна
4. Опасная работа
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Снегурка для опера Морозова

Восхождение Примарха 7

Дубов Дмитрий
7. Восхождение Примарха
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Восхождение Примарха 7

Хуррит

Рави Ивар
Фантастика:
героическая фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Хуррит

Рождение победителя

Каменистый Артем
3. Девятый
Фантастика:
фэнтези
альтернативная история
9.07
рейтинг книги
Рождение победителя

Ты не мой Boy 2

Рам Янка
6. Самбисты
Любовные романы:
современные любовные романы
короткие любовные романы
5.00
рейтинг книги
Ты не мой Boy 2

Метатель. Книга 2

Тарасов Ник
2. Метатель
Фантастика:
боевая фантастика
попаданцы
рпг
фэнтези
фантастика: прочее
постапокалипсис
5.00
рейтинг книги
Метатель. Книга 2

Право налево

Зика Натаэль
Любовные романы:
современные любовные романы
8.38
рейтинг книги
Право налево

Имя нам Легион. Том 2

Дорничев Дмитрий
2. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 2

Сумеречный стрелок 8

Карелин Сергей Витальевич
8. Сумеречный стрелок
Фантастика:
городское фэнтези
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Сумеречный стрелок 8

Кодекс Охотника. Книга VIII

Винокуров Юрий
8. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга VIII

Сильнейший ученик. Том 2

Ткачев Андрей Юрьевич
2. Пробуждение крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Сильнейший ученик. Том 2

Последняя Арена 4

Греков Сергей
4. Последняя Арена
Фантастика:
рпг
постапокалипсис
5.00
рейтинг книги
Последняя Арена 4