C# 4.0 полное руководство - 2011
Шрифт:
Вот к какому результату приводит выполнение этой программы.
Координаты точки а: 1, 2, 3
Координаты точки Ь: 10, 10, 10
Результат сложения а+Ь: 11, 12, 13 Результат присваивания i = а: 6
Результат вычисления выражения а * 2 - Ь: -988
Как следует из приведенного выше примера программы, когда объект типа ThreeD используется в таком целочисленном выражении, как i = а, происходит его преобразование. В этом конкретном случае преобразование приводит
Но для различных целей можно создать разные операторы преобразования. Так, для преобразования объекта типа ThreeD в тип double можно было бы определить второй оператор преобразования. При этом каждый вид преобразования выполнялся бы автоматически и независимо от другого.
Оператор неявного преобразования применяется автоматически в следующих случаях: когда в выражении требуется преобразование типов; методу передается объект; осуществляется присваивание и производится явное приведение к целевому типу. С другой стороны, можно создать оператор явного преобразования, вызываемый только тогда, когда производится явное приведение типов. В таком случае оператор явного преобразования не вызывается автоматически. В качестве примера ниже приведен вариант предыдущей программы, переделанный для демонстрации явного преобразования в тип int.
// Применить явное преобразование, using System;
// Класс для хранения трехмерных координат, class ThreeD {
int х, у, z; // трехмерные координаты public ThreeD { х = у = z = 0; }
public ThreeD(int i, int j, int k) { x = i; у = j; z = k; }
// Перегрузить бинарный оператор +.
public static ThreeD operator +(ThreeD opl, ThreeD op2)
{
ThreeD result = new ThreeD;
result.x = opl.x + op2.x; result.у = opl.у + op2.y; result.z = opl.z + op2.z;
return result;
}
// Выполнить на этот раз явное преобразование типов, public static explicit operator int(ThreeD opl)
{
return opl.x * opl.у * opl.z;
}
// Вывести координаты X, Y, Z. public void Show
{
Console.WriteLine(x + ", " + у + ", " + z) ;
}
}
class ThreeDDemo { static void Main {
ThreeD a = new ThreeD(1, 2, 3) ;
ThreeD b = new ThreeD(10, 10, 10);
ThreeD с = new ThreeD; int i;
Console.Write("Координаты точки a: ");
a.Show;
Console.WriteLine ;
Console.Write("Координаты точки b: ");
b.Show ;
Console.WriteLine ;
с = a + b; // сложить координаты точек а и b Console.Write("Результат сложения a + b: ");
c.Show;
Console.WriteLine ;
i = (int) a; // преобразовать в тип int явно,
// поскольку указано приведение типов Console.WriteLine("Результат присваивания i =
а: " + i) ;Console.WriteLine;
i = (int)a * 2 - (int)b; // явно требуется приведение типов Console.WriteLine("Результат вычисления выражения а * 2 - b: " + i) ;
}
}
Оператор преобразования теперь указан в явной форме, и поэтому преобразование должно быть явно приведено к типу int. Например, следующая строка кода не будет скомпилирована, если исключить приведение типов.
i = (int) а; // преобразовать в тип int явно,
// поскольку указано приведение типов
На операторы преобразования накладывается ряд следующих ограничений.
• Исходный или целевой тип преобразования должен относиться к классу, для которого объявлено данное преобразование. В частности, нельзя переопределить преобразование в тип int, если оно первоначально указано как преобразование в тип double.
• Нельзя указывать преобразование в класс ob j ect или же из этого класса.
• Для одних и тех же исходных и целевых типов данных нельзя указывать одновременно явное и неявное преобразование.
• Нельзя указывать преобразование базового класса в производный класс. (Подробнее о базовых и производных классах речь пойдет в главе 11.)
• Нельзя указывать преобразование в интерфейс или же из него. (Подробнее об интерфейсах — в главе 12.)
Помимо указанных выше ограничений, имеется ряд рекомендаций, которыми обычно руководствуются при выборе операторов явного или неявного преобразования. Несмотря на все преимущества неявных преобразований, к ним следует прибегать только в тех случаях, когда преобразованию не свойственны ошибки. Во избежание подобных ошибок неявные преобразования должны быть организованы только в том случае, если удовлетворяются следующие условия. Во-первых, информация не теряется, например, в результате усечения, переполнения или потери знака. И во-вторых, преобразование не приводит к исключительной ситуации. Если же неявное преобразование не удовлетворяет этим двум условиям, то следует выбрать явное преобразование.
Рекомендации и ограничения по перегрузке операторов
Действие перегружаемого оператора распространяется на класс, для которого он определяется, и никак не связано с его первоначальным применением к данным встроенных в C# типов. Но ради сохранения ясности структуры и удобочитаемости исходного кода перегружаемый оператор должен, по возможности, отражать основную суть своего первоначального назначения. Например, назначение оператора + для класса ThreeD по сути не должно заметно отличаться от его назначения для целочисленных типов данных. Если бы, например, определить оператор + относительно некоторого класса таким образом, чтобы по своему действию он стал больше похожим на оператор /, то вряд ли от этого было бы много проку. Главный принцип перегрузки операторов заключается в следующем: несмотря на то, что перегружаемый оператор может получить любое назначение, ради ясности новое его назначение должно быть так или иначе связано с его первоначальным назначением.
На перегрузку операторов накладывается ряд ограничений. В частности, нельзя изменять приоритет любого оператора или количество операндов, которое требуется для оператора, хотя в операторном методе можно и проигнорировать операнд. Кроме того, имеется ряд операторов, которые нельзя перегружать. А самое главное, что перегрузке не подлежит ни один из операторов присваивания, в том числе и составные, как, например, оператор +=. Ниже перечислены операторы, которые нельзя перегружать. Среди них имеются и такие операторы, которые будут рассматриваться далее в этой книге.