Российский Государственный Технологический Университет им. К.Э. Циолковского
Опубликован: 02.03.2007 | Доступ: свободный | Студентов: 5678 / 802 | Оценка: 3.96 / 3.45 | Длительность: 27:04:00
ISBN: 978-5-9556-0086-4
Лекция 6:

Перегруженные операции

< Лекция 5 || Лекция 6: 123 || Лекция 7 >
Аннотация: Основная конструкция C# – объявление класса. Класс есть тип. Тип характеризуется неизменяемым набором свойств и методов. Для предопределенных типов определены множества операций, которые кодируются с использованием множества определенных в языке символов операций. Мощнейшее средство языка C# перегрузка операций обсуждается в этой лекции

Основная конструкция C# – объявление класса. Класс есть тип. Тип характеризуется неизменяемым набором свойств и методов. Для предопределенных типов определены множества операций, которые кодируются с использованием множества определенных в языке символов операций.

Язык позволяет строить сложные выражения с использованием этих операций, причем результат выполнения (определения результирующего значения) зависит от типа элементарных выражений, составляющих сложное выражение. Например, операция сложения для целочисленных значений определяется и выполняется иначе, нежели сложение для чисел с плавающей точкой.

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

Для построения сложных выражений на основе элементарных выражений производных типов C# предоставляет те же возможности, что и для выражений предопределенных типов. Главная проблема заключается в том, что алгоритм вычисления значения выражения, представленного операндами вновь объявляемого типа в сочетании с символами операций, применяемых с операндами данного типа, неизвестен. Правила вычисления значения для такого выражения должны быть специальным образом определены программистом при определении класса. Эти правила (алгоритм вычисления значения выражения) задаются при определении функций специального вида, выражения вызова которых внешне напоминают выражения, построенные на основе операндов предопределенного типа и соответствующих символов операций.

Перегрузка операций

Перегрузка операций в C# является способом объявления семантики новых операций, которые обозначаются принятыми в C# символами операций.

Перегрузка операций строится на основе общедоступных ( public ) статических (вызываемых от имени класса) функций-членов с использованием ключевого слова operator.

Не все операции множества могут быть переопределены (перегружены) подобным образом. Некоторые операции могут перегружаться с ограничениями.

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

+, –, !, ~, ++, ––, true, false Унарные символы операций, допускающие перегрузку. true и false также являются операциями
+, –, *, /, %, &, |, ^, <<, >> Бинарные символы операций, допускающие перегрузку
==, !=, <, >, <=, >= Операции сравнения перегружаются
&&, || Условные логические операции моделируются с использованием ранее переопределенных операций & и |
[] Операции доступа к элементам массивов моделируются за счет индексаторов
() Операции преобразования реализуются с использованием ключевых слов implicit и explicit
+=, –=, *=, /=, %=, &=, =, ^=, <<=, >>= Операции не перегружаются, по причине невозможности перегрузки операции присвоения
=, ., ?:, –>, new, is, sizeof, typeof Операции, не подлежащие перегрузке

При этом при перегрузке операций для любого нового типа выполняются следующие правила:

  • префиксные операции ++ и –– перегружаются парами;
  • операции сравнения перегружаются парами: если перегружается операция ==, также должна перегружаться операция !=. То же самое относится к парам < и >, <= и >=.

Операторная функция. Объявление

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

  • определяется статическая операторная функция особого вида (синтаксис объявления рассматривается ниже), в заголовке которой указывается символ переопределяемой операции;
  • в теле функции реализуется соответствующий алгоритм, определяющий семантику операторной функции (семантику новой операции);
  • выражение вызова операторной функции имитирует внешний вид выражения, построенного на основе соответствующего символа операции;
  • при трансляции выражения, включающего символы операций, производится анализ типов операндов данного выражения, на основе которого идентифицируется соответствующая операторная функция, которой и обеспечивается передача управления (возможно, что при этом автоматически реконструируется соответствующее выражение вызова операторной функции).

Синтаксис объявления операторных функций представлен в виде множества БНФ:

operator–declaration ::= 
attributes opt operator–modifiers operator–declarator operator–body 

operator–modifiers 	::= operator–modifier
                 	::= operator–modifiers operator–modifier

operator–modifier 	::= public | static | extern 
operator–declarator	::= unary–operator–declarator
                 	::= binary–operator–declarator
                 	::= conversion–operator–declarator 

unary–operator–declarator ::=
   type operator overloadable–unary–operator (type identifier)
overloadable–unary–operator   ::= + 
                            ::= –
                            ::= !
                            ::= ~
                            ::= ++
                            ::= ––
                            ::= true
                            ::= false 

binary–operator–declarator ::= 
   type operator overloadable–binary–operator (type identifier , type identifier) 
overloadable–binary–operator    ::= +
                             ::= –
                             ::= *
                             ::= /
                             ::= %
                             ::= &
                             ::= |
                             ::= ^
                             ::= <<
                             ::= >>
                             ::= ==
                             ::= !=
                             ::= >
                             ::= <
                             ::= >=
                             ::= <=

conversion–operator–declarator ::= implicit operator type (type identifier)
                      ::= explicit operator type (type identifier) 

operator–body ::= block
             ::= ;
Листинг 6.1.

Унарные операторные функции. Пример объявления и вызова

using System;
using System.Collections.Generic;
using System.Text;

namespace operations
{
 // Для моделирования унарных постфиксных и префиксных операций может
 // потребоваться модификация структуры класса: объявляются дополнительные
 // переменные для сохранения значений координат.

 public class Point2D
 {
  public float x,    y;
         float xTmp, yTmp;
  public Point2D()
  {
   x    = 0.0;
   y    = 0.0;
   xTmp = 0.0;
   yTmp = 0.0;
  }

  public static Point2D operator ++(Point2D par)
  { 
  // Фактическим координатам присваиваются старые значения.
  par.x = (par.xTmp)++;
  par.y = (par.yTmp)++;

  return par;
  }

  public static Point2D operator --(Point2D par)
  {
  // Фактическим координатам присваиваются новые значения.
  par.x = --(par.xTmp);
  par.y = --(par.yTmp);

  return par;
  }
  }

  class Program
  {
  static void Main(string[] args)
  {
  Point2D p = new Point2D();
  int i;

  // При этом в соответствии с объявлением,
  // унарный плюс всегда постфиксный,
  // а унарный минус всегда префиксный. 
  for (i = 0; i < 10; i++)
  {
   p++;
   Console.WriteLine("{0:F3},{1:F3}",p.x, p.y);
  }
            Console.WriteLine("============================================");
for (i = 0; i < 10; i++)
{
++p;
Console.WriteLine("{0:F3},{1:F3}", p.x, p.y);
}
Console.WriteLine("============================================");
for (i = 0; i < 10; i++)
{
p--;
Console.WriteLine("{0:F3},{1:F3}", p.x, p.y);
}
            Console.WriteLine("============================================");
for (i = 0; i < 10; i++)
{
--p;
Console.WriteLine("{0:F3},{1:F3}", p.x, p.y);
}
}
}
}
Листинг 6.2.
< Лекция 5 || Лекция 6: 123 || Лекция 7 >
kewezok kewezok
kewezok kewezok
Елена Шляхт
Елена Шляхт
Объясните плиз в чем отличие а++ от ++а
Почему результат разный?
int a=0, b=0;
Console.WriteLine(a++); //0
Console.WriteLine(++b); //1
a++;
++b;
Console.WriteLine(a); //2
Console.WriteLine(b); //2