Перегрузка укороченных логических операторов 


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



ЗНАЕТЕ ЛИ ВЫ?

Перегрузка укороченных логических операторов



 

Для того чтобы применение укороченных логических операторов «&&» и «||» стало возможным, необходимо соблюсти следующие четыре правила:

  • В классе должна быть произведена перегрузка логических операторов «&» и «|».
  • Перегружаемые методы операторов «&» и «|» должны возвращать значение того же типа, что и у класса, для которого эти операторы перегружаются.
  • Каждый параметр должен содержать ссылку на объект того класса, для которого перегружается логический оператор.
  • Для класса должны быть перегружены операторы true и false.

 

Если все эти условия выполняются, то укороченные логические операторы автоматически становятся пригодными для применения. Давайте рассмотрим пример:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace LC_Console

{

class MyArr

{

// Координаты точки в трехмерном пространстве

public int x, y, z;

 

public MyArr(int x = 0, int y = 0, int z = 0)

{

this.x = x;

this.y = y;

this.z = z;

}

// Перегружаем логический оператор &

public static MyArr operator &(MyArr obj1, MyArr obj2)

{

if (((obj1.x > 0) && (obj1.y > 0) && (obj1.z > 0))

& ((obj2.x > 0) && (obj2.y > 0) && (obj2.z > 0)))

return obj1;

return new MyArr(1, 1, 1);

}

// Перегружаем логический оператор |

public static MyArr operator |(MyArr obj1, MyArr obj2)

{

if (((obj1.x > 0) || (obj1.y > 0) || (obj1.z > 0))

| ((obj2.x > 0) || (obj2.y > 0) || (obj2.z > 0)))

return obj1;

return new MyArr(1, 1, 1);

}

// Перегружаем логический оператор!

public static bool operator!(MyArr obj1)

{

if ((obj1.x > 0) && (obj1.y > 0) && (obj1.z > 0))

return false;

return true;

}

// Перегружаем оператор true

public static bool operator true(MyArr obj)

{

if ((obj.x > 0) || (obj.y > 0) || (obj.z > 0))

return true;

return false;

}

// Перегружаем оператор false

public static bool operator false(MyArr obj)

{

if ((obj.x > 0) && (obj.y > 0) && (obj.z > 0))

return false;

return true;

}

// Вспомогательный метод

public static bool And(MyArr obj1, MyArr obj2)

{

if (obj1 && obj2)

return true;

return false;

}

}

 

class Program

{

static void Main(string[] args)

{

const string STR = "Координаты объектов";

MyArr obj1 = new MyArr(x: 4, z: 5, y: 12);

MyArr obj2 = new MyArr(x: 10, z: 3, y: 5);

if (MyArr.And(obj1, obj2))

Console.WriteLine(STR + " obj1 и obj2 находятся в допустимых пределах.");

else Console.WriteLine(STR + "obj1 или obj2 находятся в НЕдопустимых пределах.");

Console.WriteLine("Для продолжения нажмите любую клавишу...");

Console.ReadKey();

}

}

}

/* Выведет:

* Координаты объектов obj1 и obj2 находятся в допустимых пределах.

* Для продолжения нажмите любую клавишу...

*/

 

Благодаря тому, что все необходимые правила соблюдены, укороченные операторы становятся доступными для применения к объектам MyArr. Они действуют следующим образом. Первый операнд проверяется с помощью операторного метода operator true (для оператора «||») или же с помощью операторного метода operator false (для оператора «&&»). Если удается определить результат данной операции, то соответствующий перегружаемый оператор («&» или «|») далее не выполняется. В противном случае перегружаемый оператор («&» или «|» соответственно) используется для определения конечного результата. Следовательно, когда применяется укороченный логический оператор «&&» или «||», то соответствующий логический оператор «&» или «|» вызывается лишь в том случае, если по первому операнду невозможно определить результат вычисления выражения.

Описанный выше способ применения укороченных логических операторов может показаться, на первый взгляд, несколько запутанным, но если подумать, то в таком применении обнаруживается известный практический смысл. Ведь благодаря перегрузке операторов true и false для класса компилятор получает разрешение на применение укороченных логических операторов, не прибегая к явной их перегрузке.Это дает также возможность использовать объекты в условных выражениях. И вообще, логические операторы & и | лучше всего реализовывать полностью, если, конечно, не требуется очень узко направленная их реализация.

 

4.2.7. Ещё раз об операторах преобразования

Ещё раз об операторах преобразования

 

Иногда объект определённого класса требуется использовать в выражении, включающем в себя данные других типов. В одних случаях для этой цели оказывается пригодной перегрузка одного или более операторов, а в других случаях — обыкновенное преобразование типа класса в целевой тип. Для подобных ситуаций в С# предусмотрена специальная разновидность операторного метода, называемая оператором преобразования. Такой оператор преобразует объект исходного класса в другой тип. Операторы преобразования помогают полностью интегрировать типы классов в среду программирования на С#, разрешая свободно пользоваться классами вместе с другими типами данных, при условии, что определен порядок преобразования в эти типы.

Существуют две формы операторов преобразования: явная и неявная. Ниже они представлены в общем виде:

 

public static explicit operator <целевой тип>(<исходный тип> v) {return <значение>;}

public static implicit operator <целевой тип>(<исходный тип> v) {return <значение>;}

 

Где целевой тип обозначает тот тип, в который выполняется преобразование; исходный тип — тот тип, который преобразуется; значение — конкретное значение, приобретаемое классом после преобразования. Операторы преобразования возвращают данные, имеющие целевой тип, причем указывать другие возвращаемые типы данных не разрешается.

Если оператор преобразования указан в неявной форме (implicit), то преобразование вызывается автоматически, например, в том случае, когда объект используется в выражении вместе со значением целевого типа. Если же оператор преобразования указан в явной форме (explicit), то преобразование вызывается в том случае, когда выполняется приведение типов. Для одних и тех же исходных и целевых типов данных нельзя указывать оператор преобразования одновременно в явной и неявной форме.

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace ConsoleApplication1

{

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace LC_Console

{

class UserInfo

{

public string Name, Family;

public byte Age;

 

public UserInfo(string Name, string Family, byte Age)

{

this.Name = Name;

this.Family = Family;

this.Age = Age;

}

// Явное преобразование типа UserInfo к string

public static explicit operator string(UserInfo obj)

{

return "Информация о пользователе: " + obj.Name + " " + obj.Family + " (" +obj.Age+" года).";

}

}

 

class Program

{

static void Main(string[] args)

{

UserInfo ui1 = new UserInfo(Name: "John", Family: "A.", Age: 24);

string s = (string)ui1;

Console.WriteLine(s);

Console.WriteLine("Для продолжения нажмите любую клавишу...");

Console.ReadKey();

}

}

}

/* Выведет:

* Информация о пользователе: John A. (24 года).

* Для продолжения нажмите любую клавишу...

*/

 

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

 

На операторы преобразования накладывается ряд следующих ограничений:

  • Исходный или целевой тип преобразования должен относиться к классу, для которого объявлено данное преобразование. В частности, нельзя переопределить преобразование в тип int, если оно первоначально указано как преобразование в тип double.
  • Нельзя указывать преобразование в класс object или же из этого класса.
  • Для одних и тех же исходных и целевых типов данных нельзя указывать одновременно явное и неявное преобразование.
  • Нельзя указывать преобразование базового класса в производный класс.
  • Нельзя указывать преобразование в интерфейс или же из него.

 

Помимо указанных выше ограничений, имеется ряд рекомендаций, которыми обычно руководствуются при выборе операторов явного или неявного преобразования. Несмотря на все преимущества неявных преобразований, к ним следует прибегать только в тех случаях, когда преобразованию не свойственны ошибки. Во избежание подобных ошибок неявные преобразования должны быть организованы только в том случае, если удовлетворяются следующие условия. Во-первых, информация не теряется, например, в результате усечения, переполнения или потери знака. И во-вторых, преобразование не приводит к исключительной ситуации. Если же неявное преобразование не удовлетворяет этим двум условиям, то следует выбрать явное преобразование.

Наследование и полиморфизм

Основы наследования

Основы наследования

 

Наследование является одним из трех основополагающих принципов объектно-ориентированного программирования, поскольку оно допускает создание иерархических классификаций. Благодаря наследованию можно создать общий класс, в котором определяются характерные особенности, присущие множеству связанных элементов. От этого класса могут затем наследовать другие, более конкретные классы, добавляя в него свои индивидуальные особенности.

В языке С# класс, который наследуется, называется базовым, а класс, который наследует, — производным. Следовательно, производный класс представляет собой специализированный вариант базового класса. Он наследует все переменные, методы, свойства и индексаторы, определяемые в базовом классе, добавляя к ним свои собственные элементы.

Поддержка наследования в С# состоит в том, что в объявление одного класса разрешается вводить другой класс. Для этого при объявлении производного класса указывается базовый класс. При установке между классами отношения «является» строится зависимость между двумя или более типами классов. Базовая идея, лежащая в основе классического наследования, заключается в том, что новые классы могут создаваться с использованием существующих классов в качестве отправной точки:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace LC_Console

{

class Site

{

const string ADDR = "http:\\microsfot.com";

public string windows, type;

public double verOS;

private string inf;

 

public void InfoMS()

{

Console.WriteLine("Сайт: {0}\nПродукт: {1}\nТип: {2}\nВерсия ОС:{3}", ADDR, windows, type, verOS);

}

}

// Объявляем класс, унаследованный от класса Site

class W7: Site

{

public string name;

// Поля класса Site доступны через конструктор наследуемого класса

public W7(string windows, string type, double verOS, string name)

{

this.windows = windows;

this.type = type;

this.verOS = verOS;

this.name = name;

}

 

public void NameOS()

{

Console.WriteLine("Название ОС: " + name);

}

}

 

class Program

{

static void Main()

{

W7 obj = new W7(windows: "Windows", type: "На базе ядра Windows NT", verOS: 6.1, name: "Windows 7");

obj.InfoMS();

obj.NameOS();

Console.WriteLine("Для продолжения нажмите любую клавишу...");

Console.ReadKey();

}

}

}

 

Рис. 1. 1. Результат работы кода выше

 

Всякий раз, когда один класс наследует от другого, после имени базового класса указывается имя производного класса, отделяемое двоеточием. В С# синтаксис наследования класса удивительно прост и удобен в использовании. Ниже представлено схематичное представление класса W7 из вышеуказанного примера:

 

Рис. 1. 2. Наследование в коде выше

 

Как видим класс W7 получает доступ к полям и методам класса Site. Всегда надо помнить, что наследование предохраняет инкапсуляцию, а потому приватные члены никогда не могут быть доступны через ссылку на объект. Т.е. поле inf из примера не может быть доступно для вызова с помощью экземпляра класса obj.

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

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

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



Поделиться:


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

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