Overloading Operators

ในบทนี้ คุณจะได้รู้จักและการใช้งานกับ Overloading Operators ในภาษา C# ซึ่งเป็นการเปลี่ยนการทำงานของตัวดำเนินการทางคณิตศาสตร์พื้นฐานให้สามารถทำงานกับออบเจ็คได้เหมือนกับการใช้งานกับประเภทข้อมูลพื้นฐาน (Primitive data type) ในภาษา C#

Overloading Operators คืออะไร

Overloading Operators คือการเปลี่ยนแปลงวิธีการทำงานของตัวดำเนินการทางคณิตศาสตร์ให้ทำงานตามที่ต้องการ ยกตัวอย่างเช่น ในการบวกเลขสองตัวนั้น เป็นการนำค่าของพวกมันมารวมกัน ซึ่งมันใช้ได้กับตัวเลข เช่น 2 + 3 = 5

แต่สำหรับข้อมูลแบบอื่นเช่น ต้องการเอาน้ำสองแก้วมารวมกัน ข้อมูลที่มีอาจจะเป็นรัศมีของแก้ว หรืออื่นๆ ถ้าหากแก้วนั้นเป็นเหมือนออบเจ็ค มันจึงทำให้การทำงานเมื่อนำมารวมกันนั้น ไม่ได้เป้นเหมือนตัวเลข แต่เราใช้เครื่องหมาย + เช่นเดิม ดังนั้น ในบทนี้คุณจะได้เรียนรู้เกี่ยวกับ Operator overloading กับออบเจ็ค ซึ่งเป็นความสามารถหนึ่งในภาษา C# ที่จะทำให้การทำงานกับออบเจ็คนั้นง่ายและรวดเร็วมากขึ้น

นี่เป็นรูปแบบของการทำ Overloading Operators ในภาษา C#

class MyClass
{
    public static MyClass1 operator + (MyClass2 a, MyClass3 b)
    {
        MyClass c = b;
        return c;
    }
}

จากรูปแบบข้างบนนั้นเป็นการทำ Overloading operators สำหรับคลาส MyClass1 สำหรับเครื่องหมาย + (บวก) โดยสร้างฟังก์ชันภายในคลาสนั้นให้เป็น static เพราะว่าตัวดำเนินการนี้จะสามารถนำไปใช้กับออบเจ็คใดๆ ที่สร้างจากคลาสนี้ และใช้คำสั่ง operator ตามด้วยเครื่องหมายที่ทำการ Overload และส่งอากิวเมนต์สองตัวสำหรับ operand ทั้งสอง

การสร้างและการใช้ Overloading Operators

เพื่อให้คุณเข้าใจว่าทำไมเราจึงต้องทำ Operator overloading มาดูตัวอย่างต่อไปนี้

int a = 2;
int b = 3;
int c = a + b;
int d = a - b;

ในตัวอย่าง เรามีตัวแปร a และ b และได้กำหนดค่าให้กับตัวแปรเหล่านั้น หลังจากนั้นเราหาผลรวมโดยการใช้ตัวดำเนินการ + และหาผลต่างโดยการใช้ตัวดำเนินการ - ซึ่งตัวดำเนินการเหล่านี้สามารถใช้ได้กับ Primitive data type อยู่แล้ว แต่การ Operator overloading นั้นจะทำให้เราสามารถใช้ตัวดำเนินการได้กับออบเจ็ค ตามความหมายที่เรากำหนดขึ้น

ต่อไปมาดูตัวอย่างการใช้งาน Operator overloading ในภาษา C# ซึ่งจะเป็นโปรแกรมในการหาผมรวม ผลต่าง และระยะหว่าง ระหว่างจุดสองมิติ โดยการใช้ตัวดำเนินการที่ได้จากการทำ Operator overloading

using System;

class OperatorOverloading
{
    static void Main(string[] args)
    {
        Vector2D vector1 = new Vector2D(2, 3);
        Vector2D vector2 = new Vector2D(-1, 5);

        Vector2D add = vector1 + vector2;
        Vector2D subtract = vector1 - vector2;
        double distance = vector1 / vector2;

        Console.WriteLine("Vector 1 " + vector1.GetPoint());
        Console.WriteLine("Vector 2 " + vector1.GetPoint());
        Console.WriteLine("Add vector " + add.GetPoint());
        Console.WriteLine("Subtract vector " + subtract.GetPoint());
        Console.WriteLine("Distance " + distance);
    }
}

class Vector2D
{

    public int x;
    public int y;

    public Vector2D(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public string GetPoint()
    {
        return "[" + x + ", " + y + "]";
    }

    public static Vector2D operator +(Vector2D a, Vector2D b)
    {
        int x = a.x + b.x;
        int y = a.y + b.y;
        Vector2D c = new Vector2D(x, y);
        return c;
    }

    public static Vector2D operator -(Vector2D a, Vector2D b)
    {
        int x = a.x - b.x;
        int y = a.y - b.y;
        Vector2D c = new Vector2D(x, y);
        return c;
    }

    public static double operator /(Vector2D a, Vector2D b)
    {
        double x = Math.Pow(a.y - a.x, 2) + Math.Pow(b.y - b.x, 2);
        return Math.Sqrt(x);
    }
}

ในตัวอย่าง เป็นโปรแกรมในการทำงานกับ Vector 2 มิติ เราได้สร้างคลาส Vector2D สำหรับเก็บข้อมูลของจุดในสองมิติ และเมธอด GetPoint() เป็นเมธอดในการรับค่าของจุด

public static Vector2D operator +(Vector2D a, Vector2D b)
{
    int x = a.x + b.x;
    int y = a.y + b.y;
    Vector2D c = new Vector2D(x, y);
    return c;
}

public static Vector2D operator -(Vector2D a, Vector2D b)
{
    int x = a.x - b.x;
    int y = a.y - b.y;
    Vector2D c = new Vector2D(x, y);
    return c;
}

ภายในคลาส Vector2D เราได้ทำการ overload ตัวดำเนินการบวก + สำหรับบวกค่าของสอง Vector ออบเจ็ค a กับ bเข้าด้วยกันที่เป็นพารามิเตอร์ และส่งค่ากลับเป็น Vector ใหม่ที่มีการรวม Vector แล้ว และสำหรับตัวดำเนินการลบ - เช่นกัน เป็นการหักล้างสอง Vector และได้ผลลัพธ์เป็นผลต่างระหว่าง Vector a กับ b

public static double operator /(Vector2D a, Vector2D b)
{
    double x = Math.Pow(a.y - a.x, 2) + Math.Pow(b.y - b.x, 2);
    return Math.Sqrt(x);
}

และทำการ overload ตัวดำเนินการหาร / สำหรับการหาระยะห่างของจุดของแรงของ Vector ในสองมิติ จากสูตรของมัน นั่นหมายความ่า เราได้เปลี่ยนการกระทำของตัวดำเนินการ / ไปแล้ว เมื่อมันใช้กับออบเจ็คของ Vector2D

Vector 1 [2, 3]
Vector 2 [2, 3]
Add vector [1, 8]
Subtract vector [3, -2]
Distance 6.08276253029822

นี่เป็นผลลัพธ์การทำงานของโปรแกรมสำหรับ Operator overloading ในภาษา C# คุณจะเห็นว่าเราสามารถใช้ตัวดำเนินการต่างๆ กับออบเจ็คที่สร้างขึ้นตามการทำงานที่เรากำหนด ซึ่งทำให้การเขียนโปรแกรมของเราสะดวกและง่ายขึ้นเป็นอย่างมาก

Operator overloading example

ต่อมาเป็นตัวอย่างเพิ่มเติมสำหรับ Operator overloading ในภาษา C# ในตัวอย่างนี้ เราจะขอยกตัวอย่างสำหรับการหาผลรวมน้ำในแก้วน้ำ โดยเราจะสร้างคลาสของแก้วน้ำขึ้นมา

using System;

namespace OverloadingOperators
{
    class Program
    {
        static void Main(string[] args)
        {
            Glass g1 = new Glass(5.2f, 8);
            Glass g2 = new Glass(3.2f, 10);

            float totalvolume = g1 + g2;
            Console.WriteLine("g1 and g2 sumation of volume = " + totalvolume);
        }     
    }  
}

class Glass
{
    const float PI = 3.14F;

    private float radius;
    private float height;

    public Glass (float r, float h) 
    {
        radius = r;
        height = h;
    }

    public static float operator +(Glass a, Glass b)
    {
        float totalvolume = a.GetVolume() + b.GetVolume();
        return totalvolume;
    }

    public float GetVolume()
    {
        return (2 * radius * 3.14f) * height;
    }
}

ในตัวอย่างเป็นการหาผลรวม ของออบเจ็คที่สร้างจากคลาส Glass และมีค่า return เป็น float โดยในคำสั่ง g1 + g2 นั้นเป็นการทำงานจากการ overloading และมเื่อรันโปรแกรมจะได้ผลลัพธ์ดังข้างล่าง

g1 and g2 sumation of volume = 462.208

เพื่อให้เข้าใจมากขึ้น การทำ overloading operators นั้นคล้ายกันกับ overloading method แต่สิ่งที่ต่างกันคือในการ return ค่าต้องเลือกสำหรับค่าใดค่าหนึ่งเท่านั้น ตัวอย่างต่อไปแทนที่เราส่งค่าผลรมของปริมาตรของแก้วทั้งสองกลับ เราจะทำการส่งแก้วใบใหม่ที่มีปริมาตรเท่าเดิมแทน

using System;

namespace OverloadingOperators
{
    class Program
    {
        static void Main(string[] args)
        {
            Glass g1 = new Glass(5.2f, 8);
            Glass g2 = new Glass(3.2f, 10);

            Glass g3 = g1 + g2;
            Console.WriteLine("g3 radius = " + g3.radius);
            Console.WriteLine("g3 height = " + g3.radius);
            Console.WriteLine("g3 volume = " + g3.GetVolume());
        }     
    }  
}

class Glass
{
    const float PI = 3.14F;

    public float radius;
    public float height;

    public Glass (float r, float h) 
    {
        radius = r;
        height = h;
    }

    public static Glass operator +(Glass a, Glass b)
    {
        float totalvolume = a.GetVolume() + b.GetVolume();
        float totalArea = a.GetBaseArea() + b.GetBaseArea();

        float newRadius = totalArea / 2 / PI;
        float newHeight = totalvolume / totalArea;
        Glass c = new Glass(newRadius, newHeight);
        return c;
    }

    public float GetBaseArea()
    {
        return 2 * radius * PI;
    }

    public float GetVolume()
    {
        return (2 * radius * PI) * height;
    }
}

ในตัวอย่าง นั้นเป็นการสร้าง overloading operators สำหรับออบเจ็คจากคลาส Glass เช่นเดิม แต่ตอนนี้ค่าที่ส่งกลับจำเป็นออบเจ็คของ Glass เช่นเดิม ที่มีปริมาตรเท่าเดิม และนี่เป็นผลลัพธ์เมื่อรันโปรแกรม

g3 radius = 8.4
g3 height = 8.4
g3 volume = 462.208

จากผลของโปรแกรมั้นเราได้ทำการเปลี่ยนให้เครื่องหมาย + สำหรับออบเจ็คของ Glass นั้น return ออบเจ็คของ Glass อันใหม่ ที่มีปริมาตรเท่าเดิม และมีรัศมีและความสูงใหม่เป็นอย่างที่เห็น

Overloadable operators

ในภาษา C# ส่วนมากแล้วตัวดำเนินการเกือบทุกชนิดสามารถที่ทำการ Operator overloading ได้โดยแต่ละตัวดำเนินการนั้นจะมีจำนวนของ Operand ที่แตกต่างกัน ตารางข้างล่างเป็นตัวดำเนินการที่สามารถทำการ Operator overloading ได้ในภาษา C#

OperatorsNumber of operand
+1 or 2
-1 or 2
!1
~1
++1
--1
*2
/2
%2
==2
!=2
<2
>2
<=2
>=2

ตัวอย่างของการ Operator overloading ในการใช้งานตัวดำเนินการต่างๆ

public static SomeObjectA operator - (SomeObjectB a, SomeObjectC b)
{
    // do something
    return ...; // SomeObjectA
}

public static bool operator == (SomeObjectB a, SomeObjectC b)
{
    // do something
    return ...; // bool value
}

public static SomeObjectA operator ++ (SomeObjectB a)
{
    // do something
    return ...; // SomeObjectA
}

ในตัวอย่าง เป็นรูปแบบการใช้งาน Operator overloading กับตัวดำเนินการต่างๆ ซึ่งอาจจะเป็นหนึ่งหรือสอง Operands และสำหรับการส่งค่ากลับนั้นสามารถเป็นออบเจ็คหรือ Primitive data type ก็ได้

ในบทนี้ คุณได้รู้จักและได้รู้การสร้างและการใช้งาน Overloading operators ในภาษา C# เพื่อให้การทำงานเป็นไปตามที่ต้องการได้ และมันเป็นสิ่งที่อำนวยความสะดวกในการจัดการกับออบเจ็คที่เราสร้างขึ้นมาเป็นอย่างมาก