2. Перевантаження бінарних арифметичних операцій.
Створимо клас d2Vector геометричних векторів на площині, для якого пізніше і перевантажимо ряд операцій. Визначення класу помістимо в окремий файл проекту, наприклад, d2Vector.cs.
using System;
namespace ReloadOperators {
class d2Vector
{
double x, y;
public d2Vector(double x_, double y_) // конструктор
{ x = x_; y = y_; }
// конструктор без параметрів
public d2Vector() : this(1, 1) { }
// конструктор
public d2Vector(d2Vector v) : this(v.x, v.y) { }
// заміщений метод із System.Object
public override string ToString()
{ return String.Format("x = {0} y = {1}", x, y); }
}
}
Тут заміщається метод ToString() із класу System.Object – це дозволить пізніше зручно виводити координати векторів.
У файл Program.cs помістимо метод Main(). У ньому створимо вектори a та b (які саме конструктори спрацьовують при цьому?):
using System;
namespace ReloadOperators
{
class Program
{
static void Main()
{
d2Vector a = new d2Vector(1, 2);
Console.WriteLine("a: " + a.ToString());
d2Vector b = new d2Vector(3, 5);
Console.WriteLine("b: " + b.ToString());
}
}
}
Завдяки заміщеному методу ToString() координати тепер легко виводити на екран:
a: x = 1 y = 2
b: x = 3 y = 5
Наша мета – мати змогу написати, наприклад, a = a + b або a = a * b. Це і буде означати перевантаження операцій для класу.
Додамо у визначення класу d2Vector операторні методи для операцій додавання та віднімання двох векторів:
// бінарний плюс
public static d2Vector operator +(d2Vector v1, d2Vector v2)
{
d2Vector temp = new d2Vector(v1.x + v2.x, v1.y + v2.y);
return temp;
}
// бінарний мінус
public static d2Vector operator -(d2Vector v1, d2Vector v2)
{
d2Vector temp = new d2Vector(v1.x - v2.x, v1.y - v2.y);
return temp;
}
Код цих методів цілком зрозумілий – необхідно створити новий вектор, координати якого є відповідно сумою або різницею координат двох векторів-параметрів. Це зовсім просто завдяки тому, що у нас у класі є відповідний конструктор. Далі одержаний вектор повертається як результат кожного з цих методів. Помістивши тепер у Main() інструкції
d2Vector c = new d2Vector();
c = a + b;
Console.WriteLine("c = a + b: " + c.ToString());
c = a - b;
Console.WriteLine("c = a - b: " + c.ToString());
одержимо на екрані наступні результати:
c = a + b: x = 4 y = 7
c = a - b: x = -2 y = -3
Далі реалізуємо у класі d2Vector можливість множення векторів. Тут слід мати на увазі, що вектори можна множити між собою скалярно, а також множити вектор на число і навпаки – число на вектор (для операторного методу порядок операндів суттєвий!). Таким чином нам необхідно три перевантажених методи множення векторів – при скалярному множенні результатом буде дійсне число, при множенні вектора та числа між собою – результатом буде вектор.
// скалярний добуток
public static double operator *(d2Vector v1, d2Vector v2)
{ return v1.x * v2.x + v1.y * v2.y; }
// множення вектора на число
public static d2Vector operator *(d2Vector v1, double k)
{
d2Vector temp = new d2Vector(v1.x * k, v1.y * k);
return temp;
}
// множення числа на вектор
public static d2Vector operator *(double k, d2Vector v1)
{
d2Vector temp = new d2Vector(v1.x * k, v1.y * k);
return temp;
}
Операторний метод множення числа на вектор після того, як визначене множення вектора на число можна було створити і в інший спосіб:
// множення числа на вектор
public static d2Vector operator *(double k, d2Vector v1)
{
return v1 * k; // тут викликаємо попередній метод
}
Тут просто викликається попередній операторний метод, який множить вектор на число.
Зверніть вагу, що при множенні числа та вектору для результату також створюється новий вектор, адже координати вектора-множника не повинні змінюватись, принаймні так це відбувається із справжніми векторами.
Тепер можемо протестувати новий фрагмент коду – включимо у метод Main() наступні інструкції:
double res = a * b;
Console.WriteLine("a * b = {0} ", res);
c = 2 * b;
Console.WriteLine("c = 2 * b: " + c.ToString());
c = a * 5;
Console.WriteLine("c = a * 5: " + c.ToString());
В результаті одержимо:
a * b = 13
c = 2 * b: x = 6 y = 10
c = a * 5: x = 5 y = 10
Таким чином ми створили можливість використання вбудованих операцій визначених для числових операндів також і для екземплярів нашого класу. При цьому зміст та результат операцій ми визначаємо, виходячи із змісту класу.
|