- •Тема 6. Основы программирования на языке c#
- •Условная операция
- •Операции checked и unchecked
- •Операция поглощения null
- •Безопасность типов
- •Преобразования типов
- •Неявные преобразования
- •Явные преобразования
- •Проверка равенства объектов
- •Упаковка и распаковка
- •Виртуальный метод Equals()
- •Статический метод Equals()
- •Проверка типов значений на равенство
- •Перегрузка операций
- •Как работают операции
- •Пример перегрузки операции: структура Vector
- •Добавление дополнительных перегрузок
- •Перегрузка операций сравнения
- •Пользовательские приведения
- •Реализация пользовательских приведений
- •Приведение между классами
- •Приведение между базовым и производным классами
- •Упаковывающие и распаковывающие приведения
- •Множественные приведения
Как работают операции
Чтобы понять, как перегружать операции, очень полезно задуматься о том, что происходит, когда компилятор встречает операцию в коде. Используя операцию сложения (+) в качестве примера, предположим, что компилятор обрабатывает следующие строки кода:
int myInteger = 3;
uint myUnsignedInt = 2;
double myDouble = 4.0;
long myLong = myInteger + myUnsignedInt;
double myOtherDouble = myDouble + myInteger;
Что происходит, когда компилятор встречает показанную ниже строку?
long myLong = myInteger + myUnsignedInt;
Компилятор поймет, что ему нужно сложить два целых числа и присвоить результат переменной типа long. Однако выражение mylnteger + myUnsignedInt это на самом деле интуитивно понятный и удобный синтаксис вызова метода, который складывает вместе два числа. Метод принимает два параметра myInteger и myUnsignedInt и возвращает их сумму. Таким образом, компилятор предпринимает те же действия, что и при любом вызове метода, т.е. ищет наиболее подходящую перегрузку операции сложения на основе типов параметров; в данном случае — принимающую два целых. Как и с обычными перегруженными методами, желательный тип возврата не влияет на выбор версии метода, который должен вызвать компилятор. В данном примере вызывается перегрузка, которая принимает два параметра типа int и возвращает int; затем возвращенное значение преобразуется в long.
Следующая строка заставляет компилятор использовать другую перегрузку операции сложения:
double myOtherDouble = myDouble + myInteger;
В этом экземпляре параметры имеют типы double и int, но так случилось, что не существует перегрузки операции сложения, принимающей такую комбинацию параметров. Вместо этого компилятор идентифицирует в качестве наиболее подходящей версию операции сложения с двумя параметрами типа double и неявно преобразует один int в double. Сложение двух double требует обработки, отличной от сложения двух int. Числа с плавающей точкой сохраняются в виде мантиссы и экспоненты. Их сложение включает битовый сдвиг мантиссы одного из двух параметров double таким образом, чтобы две экспоненты имели одно и то же значение, сложение мантисс, затем сдвиг мантиссы результата и настройка его экспоненты для обеспечения максимально возможной точности.
Теперь вы готовы к рассмотрению, что произойдет, если компилятор встретит пример но такой код:
Vector vectl, vect2, vect3;
// инициализировать vectl и vect2
vect3 = vectl + vect2;
vectl = vectl*2;
Здесь Vector структура, которая определена в следующем подразделе. Компилятор видит, что ему нужно сложить вместе два экземпляра Vector vectl и vect2. Он ищет перегрузку операции сложения, которая принимает в качестве параметров два экземпляра Vector.
Если компилятор находит подходящую перегрузку, он вызывает эту реализацию операции. Если же он ищет другую перегрузку операции +, которая наиболее точно подходит возможно, принимающую два параметра других типов данных, которые могут быть неявно преобразованы в экземпляры Vector. Если компилятор опять не находит подходящей перегрузки, он выдает ошибку компиляции, как он поступает всегда, когда не может найти соответствующую перегрузку при любом вызове метода.
