Добавление дополнительных перегрузок 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Добавление дополнительных перегрузок



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

Сейчас мы не станем разрабатывать полный набор, который, вероятно, понадобился бы для полнофункционального типа Vector, а просто продемонстрируем другие аспекты перегрузки операций. Для начала перегрузим операцию умножения, чтобы добавить под­держку умножения векторов на скаляры и векторов на другие векторы.

Умножение вектора на скаляр означает просто индивидуальное умножение каждо­го его компонента на скаляр; например, 2*(1.0,2.5,2.0) вернет (2.0,5.0,4.0). Соответствующая перегрузка операции выглядит следующим образом:

public static Vector operator* (double lhs, Vector rhs)

{

return new Vector(lhs*rhs.x, lhs*rhs.y, lhs*rhs.z);

}

Однако этого недостаточно. Если а и b объявлены как Vector, то это позволит напи­сать код вроде такого:

b = 2 * а;

Компилятор просто неявно преобразует целое число 2 в double, чтобы выражение со­ответствовало сигнатуре перегрузки. Однако следующий код не скомпилируется:

b = а * 2;

Дело в том, что компилятор трактует перегруженные операции точно так же, как пе­регрузку методов. Он проверяет все доступные перегрузки данной операции, чтобы оты­скать наиболее подходящий. Приведенный выше оператор требует, чтобы первый пара­метр имел тип Vector, а второй - целое число либо нечто, неявно преобразуемое в целое. Но мы не предоставили такой перегрузки. Компилятор не может поменять местами пара­метры, хотя в данном случае их порядок не важен. Придется явно определить перегрузку, которая принимает сначала Vector, а потом - double. Существуют два способа ее реа­лизации. Первый способ предполагает написание операции умножения вектора на число точно так же, как это было сделано в первом случае:

public static Vector operator* (Vector lhs, double rhs)

{

return new Vector(rhs * lhs.x, rhs * lhs.y, rhs *lhs.z);

}

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

public static Vector operator* (Vector lhs, double rhs)

{

return rhs * lhs;

}

Этот код сообщает компилятору, что если он видит умножение Vector на double, то может просто поменять порядок операндов и вызвать другую перегрузку. Какому варианту отдать предпочтение - дело вкуса. В примерах настоящей главы используется вторая вер­сия, поскольку она выглядит проще и лучше иллюстрирует идею. Эта версия также облег­чает сопровождение, поскольку позволяет избежать дублирования кода умножения в двух отдельных перегрузках.

Далее понадобится перегрузить операцию умножения для поддержки перемножения векторов. Математики предлагают множество способов перемножения векторов, но нас интересует один, известный как скалярное произведение, который возвращает в результате ска­ляр. Это повод продемонстрировать на данном примере, что арифметические операции не обязаны возвращать тип, совпадающий с типом класса, в котором они определены.

В математической терминологии, если есть два вектора - (х,у,z) и (X,Y,Z), - то значение их скалярного произведения определяется как результат выражения х*Х + y*Y + z*Z. Это может показаться странным способом перемножения таких двух вещей, но на самом деле он довольно полезен, поскольку может применяться для вычис­ления множества других показателей. Конечно, если вы пишете код, отображающий слож­ную трехмерную графику, например, использующую Direct3D или DirectDraw, то почти на­верняка обнаружите, что скалярное произведение векторов понадобится для вычисления положения объектов на экране. Что сейчас нас интересует - так это дать возможность лю­дям, использующим класс Vector, писать выражения вроде double X = а * b для вычисле­ния скалярного произведения двух объектов Vector (а и b). Соответствующая перегрузка будет выглядеть так:

public static double operator * (Vector lhs, Vector rhs)

{

return lhs.x * rhs.x + lhs.у * rhs.у + lhs.z * rhs.z;

}

Теперь, когда мы разобрались с арифметическими операциями, можно проверить их работоспособность с помощью простого тестового метода:

static void Main()

{

// демонстрация арифметических операций

Vector vect1, vect2, vect3;

vect1 = new Vector (1.0,1.5,2.0);

vect2 = new Vector(0.0,0.0,-10.0);

vect3 = vectl + vect2;

Console.WriteLine("vect1 = " + vect1);

Console.WriteLine("vect2 = " + vect2);

Console.WriteLine("vect3 = vect1 + vect2 = " + vect3);

Console.WriteLine("2*vect3 = " + 2*vect3);

vect3 += vect2;

Console.WriteLine("vect3 += vect2 дает " + vect3);

vect3 = vect1*2;

Console.WriteLine("Присваивание vect3 = vect1*2 дает " + vect3);

double dot = vect1*vect3;

Console.WriteLine("vectl*vect3 = " + dot);

}

Запуск этого кода (Vectors2. cs) даст следующий результат:

vect1 = (1, 1.5, 2)

vect2 =(0, 0, -10)

vect3 = vectl + vect2 = (1, 1.5, -8)

2*vect3 = (2, 3, -16)

vect3 += vect2 дает (1, 1.5, -18)

Присваивание vect3 = vectl*2 дает (2, 3, 4)

vect1*vect3 = 14.5

Вывод показывает, что перегруженные операции выдают корректные результаты, но если посмотреть на тестовый код внимательно, то можно удивиться, заметив, что он использует операцию, которая не была перегружена, а именно - операцию сложения с присваиванием, +=.

vect3 += vect2;

Console.WriteLine("vect3+=vect2 дает " + vect3);

Хотя += обычно считается единой операцией, она может быть разбита на два отдель­ных шага: сложение и присваивание. В отличие от языка C++, в C# на самом деле не разре­шено перегружать операцию =, но если вы перегрузите операцию +, то компилятор авто­матически использует эту перегрузку и в операции +=. Тот же принцип применим ко всем операциям присваивания, т.е. -=, *=, /=, &= и т.д.



Поделиться:


Последнее изменение этой страницы: 2016-12-30; просмотров: 131; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.139.107.241 (0.007 с.)