- •9 Перегрузка операторов
- •9.1 Основы перегрузки операторов
- •9.1.1 Перегрузка бинарных операторов
- •9.1.2 Перегрузка унарных операторов
- •9.2 Выполнение операций со встроенными в с# типами данных
- •9.3 Перегрузка операторов отношения
- •9.4 Перегрузка операторов true и false
- •9.5 Перегрузка логических операторов
- •9.5.1 Простой способ перегрузки логических операторов
- •9.5.2 Как сделать укороченные логические операторы доступными
- •9.5 Операторы преобразования
- •9.6 Рекомендации и ограничения по перегрузке операторов
- •9.6.1 Еще один пример перегрузки операторов
9.5.2 Как сделать укороченные логические операторы доступными
для применения
Для того чтобы применение укороченных логических операторов && и || стало возможным, необходимо соблюсти следующие четыре правила. Во-первых, в классе должна быть произведена перегрузка логических операторов & и |. Во-вторых, перегружаемые методы операторов & и | должны возвращать значение того же типа, что и у класса, для которого эти операторы перегружаются. В-третьих, каждый параметр должен содержать ссылку на объект того класса, для которого перегружается логический оператор. И в-четвертых, для класса должны быть перегружены операторы true и false. Если все эти условия выполняются, то укороченные логические операторы автоматически становятся пригодными для применения.
В приведенном ниже примере программы показано, как правильно реализовать логические операторы & и | в классе ThreeD, чтобы сделать доступными для применения укороченные логические операторы && и ||.
Листинг 9.11
/* Более совершенный способ перегрузки логических
операторов !, | и & для объектов класса ThreeD.
В этом варианте укороченные логические операторы && и ||
становятся доступными для применения автоматически. */
using System;
// Класс для хранения трехмерных координат.
class ThreeD
{
int x, y, z; // трехмерные координаты
public ThreeD() { x = y = z = 0; }
public ThreeD(int i, int j, int k) { x = i; y = j; z = k; }
// Перегрузить логический оператор | для укороченного вычисления.
public static ThreeD operator |(ThreeD op1, ThreeD op2)
{
if( ((op1.x != 0) || (op1.y != 0) || (op1.z != 0)) |
((op2.x != 0) || (op2.y != 0) || (op2.z != 0)) )
return new ThreeD(1, 1, 1);
else
return new ThreeD(0, 0, 0);
}
// Перегрузить логический оператор & для укороченного вычисления.
public static ThreeD operator &(ThreeD op1, ThreeD op2)
{
if( ((op1.x != 0) && (op1.y != 0) && (op1.z != 0)) &
((op2.x != 0) && (op2.y != 0) && (op2.z != 0)) )
return new ThreeD(1, 1, 1);
else
return new ThreeD(0, 0, 0);
}
// Перегрузить логический оператор !.
public static bool operator !(ThreeD op)
{
if(op) return false;
else return true;
}
// Перегрузить оператор true.
public static bool operator true(ThreeD op) {
if((op.x != 0) || (op.y != 0) || (op.z != 0))
return true; // хотя бы одна координата не равна нулю
else
return false;
}
// Перегрузить оператор false.
public static bool operator false(ThreeD op) {
if((op.x == 0) && (op.y == 0) && (op.z == 0))
return true; // все координаты равны нулю
else
return false;
}
// Вывести координаты X, Y, Z.
public void Show()
{
Console.WriteLine(x + ", " + y + ", " + z);
}
}
class TrueFalseDemo
{
static void Main()
{
ThreeD a = new ThreeD(5, 6, 7);
ThreeD b = new ThreeD(10, 10, 10);
ThreeD c = new ThreeD(0, 0, 0);
Console.Write("Координаты точки a: ");
a.Show();
Console.Write("Координаты точки b: ");
b.Show();
Console.Write("Координаты точки c: ");
c.Show();
Console.WriteLine();
if(a) Console.WriteLine("Точка a истинна.");
if(b) Console.WriteLine("Точка b истинна.");
if(c) Console.WriteLine("Точка c истинна.");
if(!a) Console.WriteLine("Точка a ложна.");
if(!b) Console.WriteLine("Точка b ложна.");
if(!c) Console.WriteLine("Точка c ложна.");
Console.WriteLine();
Console.WriteLine("Применение логических операторов & и |");
if(a & b) Console.WriteLine("a & b истинно.");
else Console.WriteLine("a & b ложно.");
if(a & c) Console.WriteLine("a & c истинно.");
else Console.WriteLine("a & c ложно.");
if(a | b) Console.WriteLine("a | b истинно.");
else Console.WriteLine("a | b ложно.");
if(a | c) Console.WriteLine("a | c истинно.");
else Console.WriteLine("a | c ложно.");
Console.WriteLine();
// А теперь применить укороченные логические операторы.
Console.WriteLine("Применение укороченных" +
"логических операторов && и ||");
if(a && b) Console.WriteLine("a && b истинно.");
else Console.WriteLine("a && b ложно.");
if(a && c) Console.WriteLine("a && c истинно.");
else Console.WriteLine("a && c ложно.");
if(a || b) Console.WriteLine("a || b истинно.");
else Console.WriteLine("a || b ложно.");
if(a || c) Console.WriteLine("a || c истинно.");
else Console.WriteLine("a || c ложно.");
}
}
Выполнение этой программы приводит к следующему результату.
Координаты точки а: 5, 6, 7
Координаты точки b: 10, 10, 10
Координаты точки с: 0, 0, 0
Точка а истинна.
Точка b истинна.
Точка с ложна.
Применение логических операторов & и |
а & b истинно.
а & с ложно.
а | b истинно.
а | с истинно.
Применение укороченных логических операторов && и ||
а && b истинно.
а && с ложно.
а || b истинно.
а || с истинно.
Рассмотрим более подробно, каким образом реализуются логические операторы & и |. Они представлены в следующем фрагменте кода.
// Перегрузить логический оператор | для укороченного вычисления.
public static ThreeD operator | (ThreeD op1, ThreeD op2)
{
if( ((opl.x != 0) || (opl.у != 0) || (opl.z != 0)) |
((op2.x != 0) || (op2.y != 0) || (op2.z != 0)) )
return new ThreeD(1, 1, 1) ;
else
return new ThreeD (0, 0, 0);
}
// Перегрузить логический оператор & для укороченного вычисления.
public static ThreeD operator &(ThreeD opl, ThreeD op2)
{
if( ((opl.x != 0) && (opl.у != 0) && (opl.z != 0)) &
((op2.x != 0) && (op2.y != 0) && (op2.z != 0)) )
return new ThreeD (1, 1,1);
else
return new ThreeD (0, 0, 0);
}
Прежде всего обратите внимание на то, что методы обоих перегружаемых логических операторов теперь возвращают объект типа ThreeD. И особенно обратите внимание на то, как формируется этот объект. Если логическая операция дает истинный результат, то создается и возвращается истинный объект типа ThreeD, у которого хотя бы одна координата не равна нулю. Если же логическая операция дает ложный результат, то соответственно создается и возвращается ложный объект. Таким образом, результатом вычисления логического выражения а & b в следующем фрагменте кода:
if(а & b) Console.WriteLine("а & b истинно.");
else Console.WriteLine("а & b ложно.");
является объект типа ThreeD, который в данном случае оказывается истинным. А поскольку операторы true и false уже определены, то созданный объект типа ThreeD подвергается действию оператора true и в конечном итоге возвращается результат типа bool. В данном случае он равен true, а следовательно, условный оператор if успешно выполняется.
Благодаря тому что все необходимые правила соблюдены, укороченные операторы становятся доступными для применения к объектам ThreeD. Они действуют следующим образом. Первый операнд проверяется с помощью операторного метода operator true (для оператора ||) или же с помощью операторного метода operator false (для оператора &&). Если удается определить результат данной операции, то соответствующий перегружаемый оператор (& или |) далее не выполняется. В противном случае перегружаемый оператор (& или | соответственно) используется для определения конечного результата. Следовательно, когда применяется укороченный логический оператор && или ||, то соответствующий логический оператор & или | вызывается лишь в том случае, если по первому операнду невозможно определить результат вычисления выражения. В качестве примера рассмотрим следующую строку кода из приведенной выше программы.
if(a || с) Console.WriteLine("а || с истинно.");
В этой строке кода сначала применяется оператор true к объекту а. В данном случае объект а истинен, и поэтому использовать далее операторный метод | нет необходимости. Но если переписать данную строку кода следующим образом:
if(c || a) Console.WriteLine ("с || а истинно.");
то оператор true был бы сначала применен к объекту с, который в данном случае ложен. А это означает, что для определения истинности объекта а пришлось бы далее вызывать операторный метод |.
Описанный выше способ применения укороченных логических операторов может показаться, на первый взгляд, несколько запутанным, но если подумать, то в таком применении обнаруживается известный практический смысл. Ведь благодаря перегрузке операторов true и false для класса компилятор получает разрешение на применение укороченных логических операторов, не прибегая к явной их перегрузке. Это дает также возможность использовать объекты в условных выражениях. И вообще, логические операторы & и | лучше всего реализовывать полностью, если, конечно, не требуется очень узко направленная их реализация.
