[C#] 08. 함수(Method)와 오버로딩과 재귀 호출


Study/C#  2020. 7. 1. 12:12

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


이 글은 C#의 함수(Method)와 오버로딩과 재귀 호출에 대한 글입니다.


프로그램을 작성해서 실행하면 Main함수에서 위에서 아래로 순차적으로 실행됩니다. 이런 순차적 방식과 제어문을 통한 분기와 반복만으로도 프로그램을 작성할 수 있습니다.

그러나 점점 프로그램이 복잡해지고 비슷한 구문이 많아진다면 이런 방식만으로는 한계가 있습니다.


그래서 프로그램에서는 이것을 극복하기 위한 함수가 있습니다. 함수는 수학에서의 함수와 같은 의미로 임의의 원소(파라미터)를 대입하므로 결과가 나오는 이항관계식을 뜻합니다.

[접근제한자] [반환 타입] 함수 이름 (파라미터)
{
  ........
  return 반환 타입;
}

정확하게 함수에 파라미터를 넣으면 함수 안의 연산을 타고 반환 타입의 형식으로 값이 반환하게 됩니다.

using System;
namespace Example
{
  class Program
  {
    // ExecuteMethod1 함수
    private static int ExecuteMethod1(int a)
    {
      // 파라미터에서 a의 값을 받으면 10을 곱해서 반환한다.
      return a * 10;
    }
    // ExecuteMethod2 함수
    private static void ExecuteMethod2(int a)
    {
      // 파라미터에서 a의 값을 받으면 콘솔 출력한다.
      Console.WriteLine(a);
    }
    // 실행 함수
    static void Main(string[] args)
    {
      // 변수 선언
      int a = 5;
      // ExecuteMethod1 함수 호출	
      // 파라미터에 5를 집어넣으면 ret의 변수에 50의 반환 값이 대입된다.
      int ret = ExecuteMethod1(a);
      // 콘솔 출력
      Console.WriteLine(ret);

      // ExecuteMethod2 함수 호출	
      // 함수 안에서 콘솔 출력
      ExecuteMethod2(a);
      // 아무 키나 누르면 종료
      Console.WriteLine("Press any key");
      Console.ReadLine();
    }
  }
}

위 소스에서 ExecuteMethod1 함수와 ExecuteMethod2 함수를 만들었습니다.

앞에 private와 static은 접근 제한자와 static 정적 타입을 설정하는 키워드인데 이것은 다른 글에서 조금 더 자세하게 설명하겠습니다.

그 외의 구조는 void와 int형의 반환형이 있습니다. void는 반환이 필요가 없다는 뜻입니다. 즉, ExecuteMethod2의 함수에서는 반환이 필요거 없습니다.

ExecuteMethod1의 함수에서는 반환형이 int형이기 때문에 함수 내에 return을 꼭 int 타입으로 반환을 해야합니다.

파라미터는 둘 다 int형을 받았습니다. 파라미터는 꼭 있어야 하는 필수 요소는 아니고 없어도 함수를 만들 수 있습니다.

Main 함수로 돌아오면 제가 ExecuteMethod1와 ExecuteMethod2를 사용했습니다.

두 함수다 파라미터를 요구하기 때문에 int형으로 된 변수를 넘깁니다. ExecuteMethod1의 경우는 반환 값이 int형이 있기 때문에 ret의 변수로 값을 받습니다.

ret를 콘솔 출력으로 확인해 보니 5의 값이 10배가 된 50이 된 것을 확인할 수 있습니다.

ExecuteMethod2함수에서 a의 변수를 넘겨서 콘솔 출력을 했습니다.


좀 더 함수의 파라미터를 복잡하게 사용해 보겠습니다.

using System;
namespace Example
{
  class Program
  {
    // ExecuteMethod1 함수
    // 파라미터 a를 참조하여 결과를 내보낼 수 있다.
    private static int ExecuteMethod1(ref int a, int b)
    {
      // b의 값에 10을 곱한다.
      b *= 10;
      // a의 값에 100을 곱한다.
      a *= 100;
      // 결과 리턴
      return b;
    }
    // ExecuteMethod2 함수
    // 함수 내의 결과를 파라미터로 내보낼 수 있다.
    private static void ExecuteMethod2(out int a)
    {
      a = 123;
    }
    // 실행 함수
    static void Main(string[] args)
    {
      // 변수 선언
      int a = 5;
      int b = 10;
      // ExecuteMethod1 함수 호출. 파라미터가 참조형(ref)이기 때문에 명시한다.
      int ret = ExecuteMethod1(ref a, b);
      // ExecuteMethod1의 반환 값 = 50	, 콘솔 출력
      Console.WriteLine("ExecuteMethod1 return = {0}", ret);
      // 콘솔 출력
      Console.WriteLine("a = {0}", a);
      Console.WriteLine("b = {0}", b);

      // ExecuteMethod2 함수 호출. 파라미터가 출력형(out)이기 때문에 명시한다.
      ExecuteMethod2(out b);
      // 콘솔 출력
      Console.WriteLine("b = {0}", b);
      // 아무 키나 누르면 종료
      Console.WriteLine("Press any key");
      Console.ReadLine();
    }
  }
}

파라미터에 ref와 out의 키워드가 있습니다. ref은 함수 외부에서 변수를 끌어오는 것을 뜻합니다.

ExecuteMethod1 함수에서 ref를 사용한 a 파라미터는 함수 내에서 값을 수정을 하면 외부에서 선언된 a 변수에 값이 변합니다.

그러나 ref를 사용하지 않은 b 파라미터는 함수 내에서 값을 수정을 하더라도 외부의 변수는 영향이 없습니다.


함수에서 반환하는 값이 여러개 일 수도 있습니다. 그럴 때 함수 반환(return)만으로는 여러개의 값을 반환할 수 없습니다.

그래서 파라미터에 out 키워드를 사용해서 파라미터로 값을 반환 할 수도 있습니다.

using System;
namespace Example
{
  class Program
  {
    // ExecuteMethod 함수
    // params 키워드를 사용하면 파라미터는 가변으로 설정된다.
    private static void ExecuteMethod(params string[] args)
    {
      // 가변 파라미터는 배열로 값을 받는다.
      foreach (string arg in args)
      {
        // 콘솔 출력
        Console.Write("{0} ", arg);
      }
      // 개행
      Console.WriteLine();
    }
    // 실행 함수
    static void Main(string[] args)
    {
      // 변수 선언
      string a = "Hello world";
      string b = "Test";
      string c = "abc";

      // ExecuteMethod 함수 호출	
      // 파라미터 a, b, c (3개)	
      ExecuteMethod(a, b, c);

      // ExecuteMethod 함수 호출	
      // 파라미터 c, b ,a , "Good." (4개)	
      ExecuteMethod(c, b, a, "Good.");
      // 아무 키나 누르면 종료
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

params의 키워드는 파라미터를 가변으로 만들 수 있습니다. 가변 파라미터란 파라미터의 개수가 정해지지 않은 뜻을 이야기합니다.

즉, ExecuteMethod의 파라미터에 3개를 넣을 수도 4개를 넣을 수도 있습니다.

ExecuteMethod 함수에서는 가변 파라미터를 배열로 받을 수 있습니다.

using System;
namespace Example
{
  class Program
  {
    // ExecuteMethod 함수
    private static int ExecuteMethod(int a)
    {
      // a가 1보다 크면
      if (a > 1)
      {
        return a * ExecuteMethod(a - 1);
      }
      else
      {
        // a보다 작으면 1를 반환한다.
        return 1;
      }
    }
    // 실행 함수
    static void Main(string[] args)
    {
      // ExecuteMethod(5)의 값은?	
      Console.WriteLine(ExecuteMethod(5));
      // 아무 키나 누르면 종료
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

위는 ExecuteMethod함수 안에서 ExecuteMethod를 호출했습니다. 함수에서 자기 자신을 호출하는 재귀 호출입니다.

재귀 호출은 수학에서의 재귀적 호출과 같은 이야기입니다. 위 식은 f(x)=x*f(x)의 식과 같습니다.

f(5)=5*f(4)를 풀게되면 5*4*3*2*1(120)입니다.즉, 팩토리얼이 됩니다.


C#은 객체 지향 언어입니다. 이 객체 지향은 사실 클래스와 아주 밀접한 기능이 있는데, 그 중 클래스의 함수를 작성할 때 다형성의 기능이 있습니다.

C#의 객체 지향에 대해서는 다른 글에서 자세히 설명하고 여기서는 다형성에 대해 설명하겠습니다.

using System;
namespace Example
{
  class Program
  {
    // ExecuteMethod 함수
    private static void ExecuteMethod(int a)
    {
      Console.WriteLine("ExecuteMethod - int - " + a);
    }
    // ExecuteMethod 함수
    private static void ExecuteMethod(string a)
    {
      Console.WriteLine("ExecuteMethod - string - " + a);
    }
    // 실행 함수
    static void Main(string[] args)
    {
      // ExecuteMethod에서 파라미터 int형 함수 호출
      ExecuteMethod(1);
      // ExecuteMethod에서 파라미터 string형 함수 호출
      ExecuteMethod("hello world");

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

사실 다형성이라고 거창한 내용은 아닙니다. 같은 이름의 함수에서 파라미터 타입이 다른 것을 뜻합니다.

위 예제를 보시면 함수에 int타입을 넣는 것이랑 string타입을 넣는 것은 호출하는 함수가 다르고 결과도 다르게 나옵니다.

왜 이런 기능이 있는 지에 대해서는 클래스의 OOP의 특성을 알아야 합니다. 다른 글에서 자세히 설명하도록 하겠습니다.

링크 - 작성중


여기까지 C#의 함수(Method)와 오버로딩과 재귀 호출에 대한 글이었습니다.


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