|
Здравствуйте! Записался на ваш курс, но не понимаю как произвести оплату. Надо ли писать заявление и, если да, то куда отправлять? как я получу диплом о профессиональной переподготовке? |
Структуры
Класс Rational или структура Rational
Вернемся к классу Rational, спроектированному в предыдущей лекции. Очевидно, что его вполне разумно представить в виде структуры. Наследование для него необязательно. Семантика присваивания развернутого типа больше подходит для рациональных чисел, чем ссылочная семантика, ведь рациональные числа - это еще один подкласс арифметического класса. В общем, класс Rational - прямой кандидат в структуры. Зададимся вопросом, насколько просто объявление класса превратить в объявление структуры? Достаточно ли заменить слово class словом struct? В данном случае заменой одного слова не обойтись. Нужно справиться и с другими вышеперечисленными ограничениями на структуры. Сделать это не трудно. И я приведу объявление структуры SRational, оставляя читателю возможность самому найти все различия между описаниями класса Rational и описанием структуры. Замечу, что, следуя правилам хорошего стиля, требующего давать полям содержательные имена, изменены имена полей. Для русскоязычных читателей английские названия, возможно, менее приятны, чем аббревиатуры m и n.
/// <summary>
/// Структура SRational.
/// определяет новый тип данных - рациональные числа и основные
/// операции над ними - сложение, умножение, вычитание и деление.
/// Рациональное число задается парой целых чисел
/// (numerator,denominator) и изображается
/// обычно в виде дроби numerator/denominator.
/// Число numerator называется числителем,
/// denominator - знаменателем. Для рационального числа существует
/// множество его представлений, например, 1/2, 2/4, 3/6, 6/12.
/// Среди всех представлений
/// можно выделить то, в котором числитель и знаменатель взаимно
/// несократимы. Такой представитель будет храниться в полях класса.
/// </summary>
public struct SRational
{
const string NONE_EXIST =
"Не существует рационального числа " +
"со знаменателем, равным нулю!";
//Поля класса. Числитель и знаменатель рационального числа.
int numerator, denominator;
/// <summary>
/// Конструктор класса. Создает рациональное число
/// эквивалентное numerator/denominator,
/// но со взаимно несократимыми числителем и знаменателем.
/// Если denominator = 0, то выбрасывается исключение,
/// сообщающее о невозможности создать
/// рациональное число со знаменателем 0
/// </summary>
/// <param name="numerator">числитель</param>
/// <param name="denominator">знаменатель</param>
public SRational(int numerator, int denominator)
{
if (denominator == 0)
throw new SRationalException(NONE_EXIST);
if (numerator == 0)
{
this.numerator = 0;
this.denominator = 1;
return;
}
//приведение знака
if (denominator < 0)
{
denominator = -denominator;
numerator = -numerator;
}
//приведение к несократимой дроби
int m = numerator, n = denominator;
{
int p = 0;
m = Math.Abs(m); n = Math.Abs(n);
do
{
p = m % n; m = n; n = p;
} while (n != 0);
}//Nod
this.numerator = numerator / m;
this.denominator = denominator / m;
}
/// <summary>
/// Представление рационального числа
/// в виде строки
/// </summary>
/// <returns>строка в формате numerator/denominator
/// </returns>
public override string ToString()
{
return numerator + "/" + denominator;
}
public SRational Plus(SRational a)
{
int u, v;
u = numerator * a.denominator + denominator * a.numerator;
v = denominator * a.denominator;
return (new SRational(u, v));
}//Plus
public static SRational operator +(SRational r1, SRational r2)
{
return (r1.Plus(r2));
}
public SRational Minus(SRational a)
{
int u, v;
u = numerator * a.denominator - denominator * a.numerator;
v = denominator * a.denominator;
return (new SRational(u, v));
}//Minus
public static SRational operator -(SRational r1, SRational r2)
{
return (r1.Minus(r2));
}
public SRational Mult(SRational a)
{
int u, v;
u = numerator * a.numerator;
v = denominator * a.denominator;
return (new SRational(u, v));
}//Mult
public static SRational operator *(SRational r1, SRational r2)
{
return (r1.Mult(r2));
}
public SRational Divide(SRational a)
{
int u, v;
u = numerator * a.denominator;
v = denominator * a.numerator;
return (new SRational(u, v));
}//Divide
public static SRational operator /(SRational r1, SRational r2)
{
return (r1.Divide(r2));
}
//Константы класса 0 и 1 - ZERO и ONE
public static readonly SRational ZERO, ONE;
SRational(int num, int den, string t)
{
numerator = num; denominator = den;
}//Закрытый конструктор
static SRational()
{
ZERO = new SRational(0, 1, "");
ONE = new SRational(1, 1, "");
}//Статический конструктор
//Операции отношения
public static bool operator ==(SRational r1, SRational r2)
{
return ((r1.numerator == r2.numerator) &&
(r1.denominator == r2.denominator));
}
public static bool operator !=(SRational r1, SRational r2)
{
return ((r1.numerator != r2.numerator) ||
(r1.denominator != r2.denominator));
}
public static bool operator <(SRational r1, SRational r2)
{
return (r1.numerator * r2.denominator <
r2.numerator * r1.denominator);
}
public static bool operator >(SRational r1, SRational r2)
{
return (r1.numerator * r2.denominator >
r2.numerator * r1.denominator);
}
public static bool operator <(SRational r1, double r2)
{
return ((double)r1.numerator / r1.denominator < r2);
}
public static bool operator >(SRational r1, double r2)
{
return ((double)r1.numerator / r1.denominator > r2);
}
public override bool Equals(object obj)
{
return this == (SRational)obj;
}
public override int GetHashCode()
{
return numerator + denominator;
}
}
/// <summary>
/// Класс, задающий исключения при работе
/// с рациональными числами.
/// </summary>
public class SRationalException : Exception
{
public SRationalException() { }
public SRationalException(string message) :
base(message) { }
public SRationalException(string message,
Exception e)
: base(message, e) { }
}Все ранее построенные примеры работы с классом Rational применимы и при работе со структурой SRational и будут давать эквивалентные результаты за одним исключением. При вызове конструктора без аргументов для класса Rational создается корректное рациональное число 0/1. Для структуры конструктор по умолчанию создает некорректное число 0/0. Эту ситуацию никак нельзя исправить, поскольку этот конструктор нельзя переопределить. Единственный выход - не пользоваться этим конструктором при работе со структурами.
Построим пример работы с объектами структуры SRational:
public void TwoSemantics()
{
SRational sr1 = new SRational(1, 3),
sr2 = new SRational(3, 5);
SRational sr3, sr4;
sr3 = sr1 + sr2; sr4 = sr3;
if (sr3 > 1) sr3 = sr1 + sr3 + SRational.ONE;
else sr3 = sr2 + sr3 - SRational.ONE;
Console.WriteLine("Структура SRational");
Console.WriteLine("sr1 = " + sr1.ToString());
Console.WriteLine("sr2 = " + sr2.ToString());
Console.WriteLine("sr3 = " + sr3.ToString());
Console.WriteLine("sr4 = " + sr4.ToString());
}В этом примере используются константы, работает статический конструктор, закрытый конструктор, перегруженные операции сравнения, арифметические выражения над рациональными числами. В результате вычислений r3 получит значение 8/15, r4 - 14/15. Заметьте, аналогичный пример для класса Rational даст те же результаты. Для класса Rational и структуры Rational нельзя обнаружить разницу между ссылочным и развернутым присваиванием. Это связано с особенностью класса Rational - он по построению относится к неизменяемым ( immutable ) классам, аналогично классу string. Операции этого класса не изменяют поля объекта, а каждый раз создают новый объект. В этом случае можно считать, что объекты класса обладают присваиванием развернутого типа.