Study/C#

[C#] 48. Operator(연산자) 오버로드 사용법

v명월v 2021. 10. 12. 15:56

안녕하세요. 명월입니다.


이 글은 C#의 Operator(연산자) 오버로드 사용법에 대한 글입니다.


C#에서 Operator(연산자)란 더하기(+), 빼기(-)의 기호입니다.

링크 - [C#] 04. 연산자


어떤 프로그램을 배우더라도 가장 맨처음 보게 되는 것이 연산자이지 않을까 싶습니다.

그리고 오버로드(overrode)의 뜻은 프로그램에서 재정의라는 뜻입니다.

링크 - [C#] 12. 클래스 상속과 재정의(override)하는 방법과 override와 new의 차이


즉, Operator(연산자) 오버로드라는 것은 연산자를 재정의하는 뜻입니다. 즉, 우리가 사용하는 더하기(+)나 빼기(-)를 단순한 숫자 연산이 아닌 다른 처리로 재정의 할 수 있다는 뜻입니다.

using System;

namespace Example
{
  // 예제 클래스
  class Node
  {
    // 데이터 프로퍼티
    public int Data
    {
      get; set;
    }
    // 생성자
    public Node(int data)
    {
      this.Data = data;
    }

    // 연산자 더하기(+) 재정의 -> 하나의 Node 인스턴스에 +를 사용할 경우
    public static Node operator +(Node a)
    {
      // 인스턴스 생성(프로퍼티의 값은 같으나 인스턴스가 다른 클래스)
      return new Node(a.Data);
    }
    // 연산자 더하기(+) 재정의 -> +의 연산자에 앞과 뒤에 Node 인스턴스가 배치된 경우
    public static Node operator +(Node a, Node b)
    {
      // 연산자 앞 인스턴스의 Data 값에 뒤 인스턴스의 Data를 더한다.
      a.Data = a.Data + b.Data;
      // 인스턴스를 리턴
      return a;
    }
    // 연산자 증감(++) 재정의 -> 전치, 후치 관계없다.
    public static Node operator ++(Node a)
    {
      // 새로운 인스턴스를 생성하며 받은 Data 값을 1 증가한다.
      return new Node(a.Data + 1);
    }
    // Operator(연산자)의 재정의(override)는 익명 함수로 설정 가능하다.
    // 새로운 인스턴스를 생성하며 Data 값을 뺀다.(참고, 더하기(+)는 인스턴스 생성이 아니지만 빼기(-)는 인스턴스 생성이다.)
    public static Node operator -(Node a, Node b) => new Node(a.Data - b.Data);
    // 묵시적 형 변환 (묵시적은 강제 캐스팅을 하지 않아도 변환된다.)
    public static implicit operator int(Node node)
    {
      // node 인스턴스의 Data 값을 리턴한다.
      return node.Data;
    }
    // 명시적 형 변환 (명시적은 강제 캐스팅을 해야 한다.)
    public static explicit operator Node(int data)
    {
      // int 형 값을 node 인스턴스를 생성해서 리턴한다.
      return new Node(data);
    }
    // Object 클래스의 ToString 함수를 재정의
    public override String ToString()
    {
      // Data 값을 String 값으로 리턴
      return Data.ToString();
    }
  }
  class Program
  {
    // 실행 함수
    static void Main(string[] args)
    {
      // Node 클래스의 명시적 형 변환으로 인해 explicit operator Node 가 호출. 인스턴스가 생성된다.
      Node node = (Node)10;
      
      // Node 클래스의 묵시적 형 변환으로 인해 implicit operator int 가 호출, int 형으로 Data 값이 나온다.
      int data = node;
      // operator + 새로운 인스턴스 생성
      Node node2 = +node;
      // operator + node의 인스턴스에 node2의 값을 더한다.
      // node와 node3은 같은 인스턴스
      var node3 = node + node2;
      // 인스턴스 주소 값 출력
      Console.WriteLine("node pointer = " + node.GetHashCode());
      // node2는 새로운 인스턴스가 생겼기 때문에 다른 인스턴스 주소값
      Console.WriteLine("node2 pointer = " + node2.GetHashCode());
      // node3은 node 인스턴스의 주소 값 복사를 했기 때문에 node와 주소값이 같다.
      Console.WriteLine("node3 pointer = " + node3.GetHashCode());
      // 연산자 증감(++) 재정의 새로운 인스턴스가 출력이 되기 때문에 node2는 영향이 없다.
      Console.WriteLine((++node2).Data);
      
      // node 인스턴스의 ToString
      Console.WriteLine("node result = " + node);
      // node2 인스턴스의 ToString
      Console.WriteLine("node2 result = " + node2);
      // node2에는 새로운 인스턴스가 생성되어 기존 node2.Data에서 node.Data를 뺀다.
      node2 -= node;
      // 콘솔 출력
      Console.WriteLine("node2 result = " + node2);

      // 아무 키나 누르면 종료
      Console.WriteLine("Press Any key...");
      Console.ReadLine();
    }
  }
}

프로그램에서 쉽게 사용되는 연산자의 재정의입니다.

기존의 정수형(int)과 실수형(float)에서는 더하기(+)나 빼기(-)를 넣으면 사칙 연산이 됩니다만, 클래스에서는 위처럼 재정의하여 사용하게 되면 코드를 많이 줄이는 효과를 줄 수 있습니다.


이 연산기호는 모든 기호가 재정의되는 것은 아닙니다.

참고 - https://docs.microsoft.com/

연산자 설명
+x, -x, !x, ~x, ++, --, true, false 파라미터가 하나인 연산자로써, 재정의가 가능하다. 여기서 true, false는 두개를 동시에 써야하는 operator로써 bool 형식으로 묵시적 형 변환이 가능한 재정의이다.
x + y, x - y, x * y, x / y, x % y, x & y, x | y, x ^ y, x << y, x >> y, x == y, x != y, x < y, x > y, x <= y, x >= y 파라미터가 두개인 연산자로써, 재정의가 가능하다.
x && y, x || y 재정의 불가, true, false 재정의로 인식된다.
a[i], a?[i] 연산자 재정의가 아닌 인덱서로 인식된다.
(T)x 형변환 재정의, explicit 명시적, implicit 묵시적
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= 재정의 불가, 단, 파라미터 두개의 연산자 재정의로 실행되어 대입된다.
^x, x = y, x.y, x?.y, c ? t : f, x ?? y, x ??= y, x..y, x->y, =>, f(x), as, await, checked, unchecked, default, delegate, is, nameof, new, sizeof, stackalloc, switch, typeof, with 재정의 불가

위 표를 참조하여 연산자 재정의가 허용됩니다.


실무에서는 사실 연산자 재정의를 잘 사용하지 않습니다. 예전 C++에서는 전처리문으로 여러가지 매크로를 만들기 위해서 사용한 적이 있던 걸로 기억되는데 C#에서는 잘 사용하지 않네요.

아마도 가독성의 문제성 때문이지 않을까 생각됩니다. 연산자를 재정의해서 사용하게 되면, 무언가 소스를 해석하기에 암호문처럼 바뀌어 버리지 않을까라고 생각되네요.

예를 들면 +연산자에 빼기 연산을 넣고 -연산자에 더하기 연산을 넣어버리면, 그냥 기호 +,-만 보기에는 더하기 빼기가 헷갈리지 않을까라고 생각되네요. 그렇게 만드는 사람은 없겠지만..


여기까지 C#의 Operator(연산자) 오버로드 사용법에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.