Здравствуйте! Записался на ваш курс, но не понимаю как произвести оплату. Надо ли писать заявление и, если да, то куда отправлять? как я получу диплом о профессиональной переподготовке? |
Структуры
Класс 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. Операции этого класса не изменяют поля объекта, а каждый раз создают новый объект. В этом случае можно считать, что объекты класса обладают присваиванием развернутого типа.