Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Операции и приведения.docx
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
200 Кб
Скачать
☆

Пример перегрузки операции: структура Vector

В этом разделе демонстрируется перегрузка операции на примере структуры Vector, представляющей трехмерный математический вектор. Не волнуйтесь, если не очень-то раз­бираетесь в математике  мы постараемся предельно упростить данный пример. Прежде всего, поясним, что трехмерный вектор  это просто три числа (типа double), которые сообщают, насколько далеко перемещается нечто. Переменные, хранящие эти три числа, называются х, у и z: х сообщает, насколько далеко нечто перемещается на восток, у  на се­вер, a z  вверх. Комбинация этих трех чисел дает итоговое перемещение. Например, если х=3.0, у=3.0 и z=l.0 (что обычно записывается как (3.0,3.0,1.0)), это значит, что вы переместились на 3 единицы на восток, 3  на север и поднялись на 1 единицу вверх.

Вы можете складывать или перемножать векторы с другими векторами или числами. Кстати, в этом контексте мы будем использовать термин скаляр, который на языке мате­матики означает просто число  в терминологии C# это обычный double. Смысл сложе­ния должен быть ясен. Если вы сначала переместитесь по вектору (3.0,3.0,1.0),а затем  по вектору (2.0,-4.0,-4.0), то результирующее перемещение может быть вы­числено простым сложением двух векторов. Сложение векторов означает индивидуальное сложение каждого из их компонентов, поэтому в результате получаем (5.0,-1.0,-3.0). В данном контексте математики пишут c=a+b, где а и b  суммируемые векторы, а с  ре­зультирующий вектор. Хорошо бы меть возможность так же обращаться со структурами Vector.

Тот факт, что в этом примере мы имеем дело со структурами, а не с классами, не важен. Перегрузка операций работает одинаково и с классами, и со структурами.

Ниже приведено определение Vector, содержащее поля-члены, конструкторы, переоп­ределение ToString(), которое позволяет легко просмотреть содержимое Vector и пере­груженную операцию.

namespace Wrox.ProCSharp.OOCSharp

{

struct Vector

{

public double x, y, z;

public Vector(double x, double y, double z)

{

this.x = x;

this.у = у;

this.z = z;

}

public Vector(Vector rhs)

{

x = rhs.x;

у = rhs.y;

z = rhs.z;

}

public override string ToString()

{

return " ( " + x + " , " + у + " , " + z + " ) ";

}

// ...

}

// ...

}

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

Конструкторы вроде второго, принимающие единственный аргумент типа Vector, часто называют конструкторами копирования, поскольку они позволяют инициализировать экземпляр класса или структуры простым копированием другого экземпляра. Обратите внимание, что для простоты мы оставляем поля структуры общедоступными (public). Их можно было бы сделать приватными (private) и написать соответствующие свойства для доступа, но это никак не повлияло бы на данный пример, за исключением того, что удли­нило бы код.

Самая интересная часть структуры Vector  перегрузка операции сложения:

public static Vector operator+ (Vector lhs, Vector rhs)

{

Vector result = new Vector(lhs);

result.x += rhs.x;

result.у += rhs.y;

result.z += rhs.z;

return result;

}

Перегрузка операции объявляется почти так же, как метод, за исключением того, что ключевое слово operator сообщает компилятору, что это на самом деле определение пе­регрузки операции. За ключевым словом operator следует символ операции, в данном случае  знак сложения (+). Возвращаемый тип  это тип, который получается после при­менения этой операции. Сложение двух векторов дает в результате вектор, поэтому здесь возвращаемым типом является Vector. В данном конкретном случае перегрузки операции сложения возвращаемый тип совпадает с включающим его классом, но, как будет показано позже, это вовсе не обязательно. Два параметра  это операнды, с которыми операция будет работать. Для бинарных операций (которые принимают два параметра), подобных сложению и вычитанию, первый параметр  это значение, которое записывается слева от знака операции, а второй  значение, записываемое справа.

Следует обратить внимание, что левые параметры принято называть lhs (left-hand side), а правыеrhs (right-handside).

C# требует чтобы перегруженные операции объявлялись как public и static; это зна­чит, что они ассоциированы с классом или структурой, а не с их экземплярами. По этой причине тело перегруженной операции не имеет доступа к нестатическим членам, а также к идентификатору this. И это нормально, потому что параметры предоставляют все вход­ные данные, необходимые операции для решения своей задачи.

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

{

Vector result = new Vector (lhs) ;

result.x += rhs.x;

result.у += rhs.y;

result.z += rhs.z;

return result;

}

Эта часть кода  точно такая же, какая могла бы быть при определении метода, и не­сложно догадаться, что она возвращает вектор, представляющий сумму lhs и rhs. Вы про­сто индивидуально складываете члены х, у и z. Теперь потребуется написать некоторый простой код, чтобы протестировать структуру Vector:

static void Main()

{

Vector vect1, vect2, vect3;

vect1 = new Vector(3.0,3.0,1.0);

vect2 = new Vector(2.0,-4.0,-4.0);

vect3 = vectl + vect2;

Console.WriteLine("vectl = " + vectl.ToString());

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

Console.WriteLine("vect3 = " + vect3.ToString());

}

Сохраним этот код в файле Vectors.cs, скомпилируем и после его запуска получим:

vect1 = (3,3,1)

vect2 = (2 ,-4,-4)

vect3 = (5,-1,-3)