Учебно-методический комплекс общее количество часов 58 ч. Лекции 28 ч


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


Download 2.46 Mb.
bet38/91
Sana19.10.2023
Hajmi2.46 Mb.
#1709453
TuriУчебно-методический комплекс
1   ...   34   35   36   37   38   39   40   41   ...   91
Bog'liq
Язык программирования C#

8.2. Перегрузка математических операторов

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


Перегрузка операторов – это еще одно средство достижения полиморфизма (изменчивости), благодаря которому одни и те же математические символы определенны над разными типами и имеют для них свой собственный смысл.
Простейший пример перегрузки операторов – это оператор “+”: он определен как над числами, так и над строками, в первом случае он просто складывает два числа, во втором соединяет две строки в одну.
Язык C# позволяет также определить операторы над собственными типами, то есть придать оператору дополнительную функциональность для работы с классами, созданными программистом. Отсюда и термин перегрузка оператора, помимо стандартной функциональности оператора, содержащийся в языке программист может придать ему и свой дополнительный смысл. Перегрузить можно только часть имеющихся в языке операторов.
Например, если у вас есть класс, используемый для хранения списка клиентов, вы можете перегрузить в нем операторы “+” для добавления клиента и “ - ” для удаления.

Программист может при помощи ключевого слова operator перегружать унарные и бинарные операторы, придерживаюсь следующих общих правил.


1. Операторы должны быть статическими.
2. Операторы должны быть открытыми
3. Операторы не могут принимать значения по ссылке.

Перегрузка бинарных операторов.


Бинарные (инфиксные) операторы используются с двумя операндами, обычно размещаемыми по обе стороны от оператора. Программист может перегрузить следующие бинарные операторы: +,-,/,%,&,|,^,<<,>>.


Общий формат для перегрузки бинарного оператора имеет следующий вид:


public static тип0 operator оператор(тип1 параметр1, тип2 параметр2)
{
тело оператора
}

В этой схеме: тип0 – тип возвращаемого оператором значения, оператор – один из доступных для перегрузки операторов, тип1 и тип2 – типы передаваемых оператору формальных параметров, паметр1 и парметр2 – имена формальных параметров.


Хотя бы один из типов формальных параметров должен совпадать с классом, для которого это оператор определен, а второй соответственно может не совпадать, при этом сам оператор может возвращать любое значение, кроме void.

class MyClass


{
public static MyClass operator &(MyClass a, MyClass b)
{
return null;
}

public static int operator +(MyClass a, int b)


{
return 0;
}
}
Лист 8.6

Для иллюстрации работы с перегрузкой операторов создадим класс для работы с комплексными числами. Комплексные числа состоят из вещественной и мнимой частей, обе эти части можно представить ч помощью типа double. Как для обычных вещественных чисел над комплексными числами определены операции сложения “+”, вычитания “-”, умножения “*” и деления “/”. Определив класс комплексных чисел и перечисленные операции в нем, мы смоделируем математическое комплексное множество.


Множество вещественных чисел в математике считается подмножеством комплексных чисел, поэтому также определим операторы, принимающие в качестве параметров не только комплексные числа, но и вещественные.

class ComplexNumber


{
// поля
public double Re, Im;

// конструктор без парметоров


public ComplexNumber()
{
Re = 0;
Im = 0;
}
// основной конструктор
public ComplexNumber(double Re, Double Im)
{
this.Re = Re;
this.Im = Im;
}

// вывод числа на консоль


public void Show()
{
if (Im >= 0)
Console.Write("{0} + {1}i\n\n", Re, Im);
if (Im < 0)
Console.Write("{0} - {1}i\n\n", Re, Math.Abs(Im));
}

// сложение двух комплексных чисел


public static ComplexNumber operator +(ComplexNumber a,
ComplexNumber b)
{
ComplexNumber c = new ComplexNumber();
c.Re = a.Re + b.Re;
c.Im = a.Im + b.Im;
return c;
}
// вычитание двух комплексных чисел
public static ComplexNumber operator -(ComplexNumber a,
ComplexNumber b)
{
ComplexNumber c = new ComplexNumber();
c.Re = a.Re - b.Re;
c.Im = a.Im - b.Im;
return c;
}
// умножение двух комплексных чисел
public static ComplexNumber operator *(ComplexNumber a,
ComplexNumber b)
{
ComplexNumber c = new ComplexNumber();
c.Re = a.Re * b.Re + a.Im * b.Im;
c.Im = a.Re * b.Im - a.Im * b.Re;
return c;
}
// деление двух комплексных чисел
public static ComplexNumber operator /(ComplexNumber a,
ComplexNumber b)
{
ComplexNumber c = new ComplexNumber();
double d = a.Re * a.Re + b.Im * b.Im;
c.Re = (a.Re * b.Re + a.Im * b.Im) / d;
c.Im = (a.Re * b.Im - a.Im * b.Re) / d;
return c;
}

// сложение комплексного и вещественного чисел


public static ComplexNumber operator +(ComplexNumber a, double b)
{
ComplexNumber c = a + new ComplexNumber(b, 0);
return c;
}
// вычитание вещественного числа из комплексного
public static ComplexNumber operator -(ComplexNumber a, double b)
{
ComplexNumber c = a - new ComplexNumber(b, 0);
return c;
}
// умножение комплексного числа на вещественное
public static ComplexNumber operator *(ComplexNumber a, double b)
{
ComplexNumber c = a * new ComplexNumber(b, 0);
return c;
}
// деление комплексного числа на вещественное
public static ComplexNumber operator /(ComplexNumber a, double b)
{
ComplexNumber c = a / new ComplexNumber(b, 0);
return c;
}

// сложение вещественного и комплексного чисел


public static ComplexNumber operator +(double a, ComplexNumber b)
{
ComplexNumber c = b + new ComplexNumber(a, 0);
return c;
}
// вычитание комплексного числа из вещественного
public static ComplexNumber operator -(double a, ComplexNumber b)
{
ComplexNumber c = b - new ComplexNumber(a, 0);
return c;
}
// умножение вещественного числа на комплексное
public static ComplexNumber operator *(double a, ComplexNumber b)
{
ComplexNumber c = b * new ComplexNumber(a, 0);
return c;
}
// деление вещественного числа на комплексное
public static ComplexNumber operator /(double a, ComplexNumber b)
{
ComplexNumber c = b / new ComplexNumber(a, 0);
return c;
}
}
Лист. 8.7

В этом относительно объемном листинге определяется класс для работы с комплексными числами ComplexNumber. Этот класс имеет два поля тип double Re и Im для хранения соответственно вещественной и мнимой частей комплексного числа, для инициализации этих полей определены два конструктора: один с параметрами, другой без, а для их вывода – метод Show().


Самое интересное в том, что этот класс содержит в себе перегрузку для бинарных операторов “+”, “-”, “*”, “/”. При том каждый оператор перегружен по три раза.
Первая перегрузка операторов позволяет производить операции с двумя комплексными числами, то есть записывать выражения типа c=a+b, где a,b,c – комплексные числа.
Вторая и третья перегрузки позволяют производить операции над комплексными и вещественными числами, то есть записывать выражения типа c=a+d и c=d+a, где c,a – комплексные числа, d – вещественное число.

Теперь протестируем созданный нами класс.


class Program


{
static void Main(string[] args)
{
ComplexNumber a, b, c;

a = new ComplexNumber(1, 1);


Console.Write("a = ");
a.Show();

b = new ComplexNumber(-5.5, 0.9);


Console.Write("b = ");
b.Show();

c = a + b;


Console.WriteLine("c = a + b");
Console.Write("c = ");
c.Show();

c = a * b;


Console.WriteLine("c = a * b");
Console.Write("c = ");
c.Show();

c = a / b;


Console.WriteLine("c = a / b");
Console.Write("c = ");
c.Show();

c = a + 5.0;


Console.WriteLine("c = a + 5.0");
Console.Write("c = ");
c.Show();

c = a * 7.5;


Console.WriteLine("c = a * 7.0");
Console.Write("c = ");
c.Show();

c = a / 100.0;


Console.WriteLine("c = a / 100.0");
Console.Write("c = ");
c.Show();

c = 5.0 + b;


Console.WriteLine("c = 5.0 + b");
Console.Write("c = ");
c.Show();

c = 7.5 * b;


Console.WriteLine("c = 7.5 * b");
Console.Write("c = ");
c.Show();

c = 100.0 / b;


Console.WriteLine("c = 100.0 / b");
Console.Write("c = ");
c.Show();
}
}
Лист. 8.8

В приведенной программе мы объявляем три объекта класса ComplexNumber a,b и c. Далее мы инициализируем объекты a и b. А объект c вычисляется с использованием всех перегруженных операторов класса ComplexNumber.


Вывод программы:

a = 1 + 1i


b = -5,5 + 0,9i


c = a + b


c = -4,5 + 1,9i

c = a * b


c = -4,6 + 6,4i

c = a / b


c = -2,5414364640884 + 3,53591160220995i

c = a + 5.0


c = 6 + 1i

c = a * 7.0


c = 7,5 - 7,5i

c = a / 100.0


c = 100 - 100i

c = 5.0 + b


c = -0,5 + 0,9i

c = 7.5 * b


c = -41,25 - 6,75i

c = 100.0 / b


c = -18,1818181818182 - 2,97520661157025i
Вывод. 8.3
Перегрузка операторов отношений.

Операторы отношений служат для сравнения двух объектов. В языке C# все переменные являются объектами, следовательно, операции отношений можно определить над любым типом. К операторам отношений относятся: “==”, “!=”, “<”, “>”, “<=”, “=>”.


Конструкции, построенные посредством операторов отношений, называются отношения.
Отношение — это логическое выражение, в котором два значения сравниваются друг с другом посредством оператора отношения.
Правила перегрузки операторов отношений практически совпадают с правилами перегрузки бинарных операторов, за исключением того, что операторы отношения должны быть перегружены парами, как показано в следующей таблице. Подобно другим бинарным операторам операторы отношений могут возвращать любой тип данных кроме void, но следует учесть, что если операторы отношений будут возвращать тип отличный от bool, то сфера их применений существенно сузится.



==

!=

<=

>=

<

>

Для иллюстрации вышесказанного добавим в наш класс ComplexNumber (Лист. 8.7) еще пару операторов: оператор проверки на равенство “==” и соответственно оператор проверки на неравенство “!=”.


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


public static bool operator ==(ComplexNumber a, ComplexNumber b)
{
if (a.Re == b.Re && a.Im == b.Im)
return true;
else
return false;
}

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


public static bool operator !=(ComplexNumber a, ComplexNumber b)
{
return !(a == b);
}
Лист. 8.9

Здесь мы перегрузили пару операторов сравнения: оператор “==” сравнивает вещественную и комплексную части числа, а оператор “!=” определен, просто как отрицание равенства.


Для тестирования этого примера добавим в конец функции Main класса Program (Лист 8.8) следующий код.

ComplexNumber d, e, f;


d = new ComplexNumber(1, 1);


Console.Write("d = ");
d.Show();

e = new ComplexNumber(1, 1);


Console.Write("e = ");
d.Show();

f = new ComplexNumber(5, 5);


Console.Write("f = ");
d.Show();

if (d == e)


Console.WriteLine("d == e\n");
if (d != e)
Console.WriteLine("d != e\n");

if (d == f)


Console.WriteLine("d == f\n");
if (d != f)
Console.WriteLine("d != f\n");
Лис. 8.10

В приведенном листинге мы объявляем три объекта типа ComplexNumber d, e и f , затем эти объекты создаются и инициализируются, после создание содержимое каждого объекта выводится на консоль. Далее объект d сравнивается с объектами e и f, а результаты сравнения выводятся на печать.


Вывод этого куска кода программы дополняет вывод 8.3 и имеет следующий вид:

d = 1 + 1i


t = 1 + 1i
f = 1 + 1i
d == e
d != f
Вывод. 8.4
Перегрузка унарных операторов.

Унарные операторы используются с одним операндом. Они могут быть префиксными, если оператор стоит перед операндом, и постфиксными, если он стоит после операнда. Программист может перегрузить следующие унарные операторы: +, -,!, ~,++,--.


Общий формат для перегрузки унарного оператора имеет следующий вид:

public static тип0 operator оператор(тип1 параметр)


{
тело оператора
}
В этой схеме: тип0 – тип возвращаемого оператором значения, оператор – один из доступных для перегрузки операторов, тип1 – тип передаваемого оператору формального параметра, этот тип должен всегда совпадать с именем класса, содержащего оператор, паметр1– имя формального параметра.
Операторы “++” и “--” должны возвращать тип, совпадающий с типом класса, содержащего оператор. Эти операторы имеют инфиксную и постфиксную формы при их перегрузке перегружаются обе, а какую выбрать решается из контекста вызова.
Операторы “+”, “-”, “!”, “~” могут возвращать любой тип.

class UnaryOverload


{
public static UnaryOverload operator ++(UnaryOverload test)
{
return null;
}

public static int operator !(UnaryOverload test)


{
return 0;
}
}
Лист. 8.11

Покажем теперь механизм работы с перегруженными унарными операторами на следующем примере. Создадим класс Vector и перегрузим в нем следующие операторы: “+”, ”-”, ”++”, ”--”.


class Vector


{
// сам вектор
public double[] TheVector;
// конструктор создает вектор и иницализирует его нулями
public Vector(int Length)
{
TheVector = new double[Length];
for (int i = 0; i < Length; i++)
TheVector[i] = 0;
}

// оператор инкремента


public static Vector operator ++(Vector Source)
{
Vector Result = new Vector(Source.TheVector.Length);
for (int i = 0; i < Source.TheVector.Length; i++)
{
++Source.TheVector[i];
Result.TheVector[i] = Source.TheVector[i];
}
return Result;
}

// оператор декремента


public static Vector operator --(Vector Source)
{
Vector Result = new Vector(Source.TheVector.Length);
for (int i = 0; i < Source.TheVector.Length; i++)
{
--Source.TheVector[i];
Result.TheVector[i] = Source.TheVector[i];
}
return Result;
}

// унарный плюс


public static Vector operator +(Vector Source)
{
Vector Result = new Vector(Source.TheVector.Length);
for (int i = 0; i < Source.TheVector.Length; i++)
Result.TheVector[i] = +Source.TheVector[i];
return Result;
}

// унарный минус


public static Vector operator -(Vector Source)
{
Vector Result = new Vector(Source.TheVector.Length);
for (int i = 0; i < Source.TheVector.Length; i++)
Result.TheVector[i] = -Source.TheVector[i];
return Result;
}

// вывод вектора


public void Show()
{
Console.Write("(");
for (int i = 0; i < TheVector.Length -1; i++)
Console.Write("{0},", TheVector[i]);
Console.Write("{0}", TheVector[TheVector.Length - 1]);
Console.WriteLine(")\n");
}
}
Лист. 8.12

В листинге определяется класс Vector. Единственное поле этого класса TheVector является массивом вещественных чисел типа double. При создании объектов класса конструктор создает массив TheVector и инициализирует его нулями.


В классе перегружены четыре унарных оператора: минус, плюс, инкремент и декремент.
Все они просто объединяют соответствующие операторы типа double для работы со всеми элементами массива TheVector.

Теперь создадим тестирующий класс для класса Vector.


class Program


{
static void Main(string[] args)
{
Vector vector = new Vector(10);
Console.Write("vector = ");
vector.Show();

vector++;


Console.WriteLine("vector++");
Console.Write("vector = ");
vector.Show();

vector = +vector;


Console.WriteLine("vector = +vector");
Console.Write("vector = ");
vector.Show();

vector = -vector;


Console.WriteLine("vector = -vector");
Console.Write("vector = ");
vector.Show();

vector--;


Console.WriteLine("vector--");
Console.Write("vector = ");
vector.Show();
}
}
Лист. 8.13

В этой программе объявляется и создается объект класса Vector vector, при создании поля этого объекта обнуляются, поэтому нет необходимости присваивать его полям новые значения. После создания состояние объекта выводится на консоль.


Затем над объектом последовательно выполняются все перегруженные в классе Vector операторы: сначала выполняется оператор инкремента, затем унарный плюс, за ним унарный минус и в конце оператор декремента. После выполнения каждого оператора состояние объекта выводится на консоль.
Вывод программы:

vector = (0,0,0,0,0,0,0,0,0,0,)


vector++
vector = (1,1,1,1,1,1,1,1,1,1,)
vector = +vector
vector = (1,1,1,1,1,1,1,1,1,1,)
vector = -vector
vector = (-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,)
vector--
vector = (-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,)
Вывод. 8.5



Download 2.46 Mb.

Do'stlaringiz bilan baham:
1   ...   34   35   36   37   38   39   40   41   ...   91




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling