Имеет ли значение порядок параметров?

Предположим, что создается структура для представления простых комплексных чисел, скажем, Complex, и требуется складывать вместе экземпляры Complex. Было бы также удобно иметь возможность прибавлять простые значения double к экземпляру Complex. Добавление такой функциональности — не проблема, поскольку можно перегрузить метод операции + так, чтобы один параметр был Complex, а другой — double. Это объявление может выглядеть примерно так:

1
static public Complex operator+( Complex lhs, double rhs )

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

1
2
Complex cpxl = new Complex ( 1.0, 2.0 );
Complex cpx2 = cpxl + 20.0;

Это избавляет от необходимости создавать дополнительный экземпляр Complex, состоящий только из реальной части, равной 20.0, чтобы добавить ее к cpxl. Однако предположим, что необходимо иметь возможность менять местами операнды и делать что-нибудь вроде следующего:

1
Complex срх2 = 20.0 + cpxl;

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

Перегрузка операции сложения

Давайте рассмотрим краткий пример структуры Complex, которая не претендует на звание исчерпывающей реализации, а просто демонстрирует перегрузку операций.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
public struct Complex
{
public Complex ( double real, double imaginary )  {
this.real = real;
this.imaginary = imaginary;
}
static public Complex Add ( Complex lhs. Complex rhs )  {
return new Complex ( lhs.real + rhs.real,
lhs.imaginary + rhs.imaginary );
}
static public Complex Add( Complex lhs, double rhs )  {
return new Complex( rhs + lhs.real,
lhs.imaginary );
}
public override string ToString()  {
return String.Format ( "({0}, {1})",
real,
imaginary ) ;
}
static public Complex operator*( Complex lhs. Complex rhs )  {
return Add( lhs, rhs );
}
static public Complex operator*( double lhs. Complex rhs )  {
return Add( rhs, lhs );
}
static public Complex operator* ( Complex lhs, double rhs )  {
return Add( lhs, rhs );
}
private double real; private double imaginary;
}
public class EntryPoint {
static void Main()  {
Complex cpxl = new Complex ( 1.0, 3.0 );
Complex cpx2 = new Complex ( 1.0, 2.0 );
Complex срхЗ = cpxl + cpx2;
Complex cpx4 = 20.0 + cpxl;
Complex cpx5 = cpxl + 25.0;
Console.WriteLine( "cpxl == {0}", cpxl );
Console.WriteLine( "cpx2 == {0}", cpx2 );
Console.WriteLine( "срхЗ == {0}", срхЗ );
Console.WriteLine( "cpx4 == {0}", cpx4 );
Console.WriteLine( "cpx5 == {0}", cpx5 );

Обратите внимание, что, как и рекомендуется, перегруженные методы операции вызывают методы, выполняющие саму операцию. Фактически это существенно упрощает поддержку обоих последовательностей операндов operator* для типа Complex.

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

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100