Главная » C# » Перегрузка операторов в Visual C# (Sharp)

0

Как было сказано, оператор + ведет себя по-разному с типами string и int. Спривается, каким образом применение оператора  + со строковым типом  изменяет его поведение? Изменить поведение оператора + можно, реализовав его в пользовельском типе.

Для примера, рассмотрим пошагово реализацию оператора + для комплексного члового типа. Комплексные числа состоят из двух частей: вещественной и мнимой. Например, в комплексном числе а+ь часть а является вещественной, а часть ь — мнимой. При сложении комплексных чисел, складываются их соответствующие вещественные и мнимые части. Далее приводится объявление комплексного числа: public sealed class ComplexType {

readonly double _real; readonly double _imaginary;

public ComplexType(double real, double imaginary) {

_real = real;

_imaginary = imaginary;

}

public double Real { get {

return _real;

}

}

public double Imaginary { get {

return „imaginary;

}

}

}

Тип compiexType является неизменяемым и имеет два члена данных, представляих вещественную и мнимую части комплексного числа.

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

CompiexType а = new CompiexType(1.О, 10.0); CompiexType b = new CompiexType(2.0, 20.0);

CompiexType с = a + b;

Перегрузка оператора + означает добавление метода, имеющего специальную нацию. Далее приводится модифицированный тип CompiexType с реализованным перегруженным оператором (соответствующий код выделен жирным шрифтом):

public sealed class CompiexType { readonly double „real;

readonly double „imaginary;

public CompiexType(double real, double imaginary) {

_real = real;

„imaginary = imaginary;

}

public double Real { get {

return „real;

}

}

public double Imaginary { get {

return „imaginary;

}

}

public static CompiexType operator +(CompiexType a, CompiexType b) { return new CompiexType (a. Real + b.Real, a.Imaginary + b. Imaginary);

}

Объявление перегруженного оператора представляет собой  объявление специалой функции, которая подчиняется следующим правилам:

•    метод всегда объявляется static в контексте типа;

•    метод имеет возвращаемый тип, которым должен быть тип, который мы хотим создать. В большинстве случаев это тип объявления;

•    идентификатор  метода  начинается  с  оператора,  после  которого  идет  пробел, а потом перегружаемый оператор (+,     ++ и т. д.);

П  параметры  метода зависят от перегружаемого оператора.  Например,  при  перрузке оператора ++ будет только один параметр.

При перегрузке операторов следует иметь в виду некоторые подводные камни. Для их понимания рассмотрим в подробностях два примера реализации оператора иремента. Для целей примеров, тип compiexType будем полагать неизменяемым.

public static CompiexType operator ++(CoitplexType a) { a.Real++;

return a;

}

public static CompiexType operator ++(CompiexType a) { return new CoitplexTypefa.Real + 1, a.Imaginary);

}

Оператор инкремента выполняет манипуляции по месту. Итак, следует ли нам волнять манипуляции по месту или создать новый экземпляр? Ответить на этот врос нелегко, т. к. если создать новый экземпляр CompiexType, то состояние паретра а необходимо полностью передать новому экземпляру.

Но обычно создается новый экземпляр, в который копируется содержимое старого экземпляра. Но этот подход имеет свои последствия, которые необходимо рассмоеть  с должной  осторожностью.  Скажем,  что  мы  создали  новый  экземпляр типа и  правильно скопировали в него состояние. В таком случае у нас будет проблема с потерей данных. Рассмотрим следующий код:

static void CallMethodfCompiexType val) { val++;

Console. WriteLine("     " + val.ToString());

}

static void Complexlncrement() {

CompiexType a = new CompiexType(1.0, 10.0);

Console.WriteLine(a.ToString()); CallMethod(a); Console.WriteLine(a.ToString());

}

Здесь метод complexlncrement создает переменную а, после чего присваивает ей значение  l. o  и  ю.о .  Генерируется  значение,  и  вывод  будет  l+ioi .  Вызывается

метод CailMethod, и значение переменной val увеличивается на единицу посредсом оператора ++. Сгенерированный вывод теперь будет 2+ioi . Когда создается последний  сгенерированный  вывод,  значение  комплексного типа должно  быть  2 и 10, но генерируется вывод  i+ioi .  Причиной этому является то обстоятельство, что ссылка на val изменилась на экземпляр нового типа.

Это переназначение происходит прозрачно, и мы не в курсе об изменении. Поэту, когда метод CailMethod завершает выполнение, он все еще ссылается на старое значение а, а не на новое. Изменение расположения оператора ++ не решает прлему. В свете этой информации  правильным решением кажется выполнение мификации по месту, но это тоже не будет работать. Правильным решением будет работа с типом compiexType как с неизменяемым, таким образом, не допуская опатора ++ и решая проблему.

Источник: Гросс  К. С# 2008:  Пер. с англ. — СПб.:  БХВ-Петербург, 2009. — 576 е.:  ил. — (Самоучитель)

По теме:

  • Комментарии