C# 프로그래밍 8번째 시간 - 메소드
유니티의 여덟걸음, C# 공부시작 35일차
오늘은 메소드(Method)에 대해서 배우겠습니다!
오늘은 C언어와 C++에서 함수의 개념을 이용하고 있는 메소드를 배워보도록 하겠습니다.
1. 메소드 (Method)
메소드란 이어지는 코드들을 묶어놓은 코드 블럭 같은 겁니다. 일단 예를 한번 들어보겠습니다.
...
static void square(int a) {
Console.WriteLine("{0}*{1}={2}", a, a, a*a);
}
...
여기에서 square에게 값을 넘겨주고, a라는 변수에서 값을 기억을 시킵니다. 그리고 a 변수를 이용하여 제곱하고 출력하는 코드를 활용합니다.
즉, 메소드는 한 값을 설정 후, 이 값이 해야되는 일을 간단하게 코드 블럭으로 나타낸 겁니다. 나중에 게임 코딩할때 유용하게 쓸 것 중 하나입니다.
메소드를 정의하는 방법을 보겠습니다.
[접근 지정자] 반환형식 메소드명(매개변수 목록) {
// 실행될 코드
}
여기서 접근 지정자는 private, public, protected 등 말 그대로 접근 가능한 범위를 지정하는 것입니다.
접근 지정자에 대한 설명은 추후에 더 자세하게 설명하겠습니다. 반환 형식은 메소드의 결과에 따라 다른데,
데이터 형식이 int형이라면 int를 쓰고, double형이면 double을 사용합니다. 만약에 반환되는 값이 없을 때는 void를 적습니다.
또 매개변수는 메소드 호출할때 값을 넘길 수 있도록 ‘매개변수’가 1개 이상 등장합니다.
반환형식을 이해해보기 위해서 예제를 한번 만들어보겠습니다.
[메소드를 이용한 예제]
using System;
namespace Study
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("{0}", Division(40, 10));
}
static int Division(int a, int b)
{
return a / b;
}
}
}
이에 대한 결과는 4가 나옵니다.
여기서 Division이 메소드라는 것입니다. 이 메소드에서는 매개변수로 두 정수를 받습니다.
우리는 10과 40이란 값을 넘겼는데, 40이란 값은 매개변수 a, 10이라는 값은 매개변수 b에 저장됩니다.
그리고 메소드가 a,b를 이용하여 결과를 만들고 return을 하면서 결과를 호출시킵니다.
return 부분을 보면, a가 40, b가 10이므로 결과는 4가 나옵니다. 그리고 return을 만나서 4라는 값을 호출된 부분으로 반환합니다.
메소드를 불러냈던 곳으로 결과를 다시 보낸다는 의미입니다. 결과가 4이기 때문에 Division(40,10)이라는 메소드에서 4라는 값이 나올 수 있습니다.
따라서 결과로 4가 출력되는 겁니다. 만약 메소드 밑에 이런 과정을 취하지 않았다면 Division메소드는 단순한 호출에만 불과하겠죠?
그리고 return의 특징 중 하나로, 이 키워드는 맨 마지막에서만 등장하는 것이 아니라 코드의 중간에서도 등장할 수 있습니다.
이 키워드는 만나면 메소드에서 빠져나간다는 것을 알고 넘어갑시다!!
2. Call by value vs Call by reference
이 두개를 이해하기 전에 매개변수의 값을 교환하는 Swap이란 함수를 이용한 예제를 만들어보겠습니다.
[Call by value를 이용한 예제]
using System;
namespace Study
{
class Program
{
static void Main(string[] args)
{
int a = 40;
int b = 10;
Console.WriteLine("교환 전: a={0}, b={1}", a, b);
Swap(a, b);
Console.WriteLine("교환 후: a={0}, b={1}", a, b);
}
static void Swap(int a, int b)
{
int temp = b;
b = a;
a = temp;
}
}
}
이에 대한 결과가 아래와 같이 나옵니다.
교환 전: a=40, b=10 <br>
교환 후: a=40, b=10 <br>
C에서 포인터와 비슷한 예문입니다. 코드를 한번 뜯어봅시다.
Swap이란 함수 내용 -> 값을 임시로 담아두는 temp라는 변수를 선언하고 여기에 값을 b의 값으로 초기화
추가로 b에 a의 값을 담은 후 a에는 temp 즉, 원래 b의 값을 담아두었음
이로써 Swap 함수는 a와 b의 값을 서로 바꿔버리는 기능을 수행합니다.
이렇게 매개변수를 변수의 값으로 가져온 경우를 Call by value(복사에 의한 함수의 호출) 이라고 합니다.
근데 이 방식을 이용하였을 때 값이 변하지 않았습니다. 우리는 b와 a의 값을 서로 변하게 하고 싶었는데 말이죠.. 왜 그럴까요!?
우리가 메소드로부터 변수를 넘겨줄 때 매개변수 a와 b가 변수 a와 b를 의미하는 게 아니라,
그냥 변수인 a와 b의 값을 매개변수 a와 b로 복사한 겁니다.
C에서 포인터와 마찬가지로 본다면 우리는 숫자만 넘겨준 것이지, 주소값을 넘겨준 것이 아닙니다.
C#으로 본다면 매개변수와 변수는 서로 별개이고, 각각 다른 메모리 공간을 사용합니다.
따라서 이건 매개변수에서의 a와 b값만 바뀐거고, 변수 a와 b의 값은 그대로입니다.
그러면 변수 a와 b의 값을 바꿔보도록 합시다.
이때는 Call by reference(참조에 의한 호출)을 이용합니다. 이는 변수의 주소값을 매개변수로 보냅니다.
직접 원래를 변수를 참조하는 방법입니다.
이를 다시 활용하여 예제를 바꿔보겠습니다.
[Call by reference를 이용한 예제]
using System;
namespace Study
{
class Program
{
static void Main(string[] args)
{
int a = 40;
int b = 10;
Console.WriteLine("교환 전: a={0}, b={1}", a, b);
Swap(ref a, ref b);
Console.WriteLine("교환 후: a={0}, b={1}", a, b);
}
static void Swap(ref int a, ref int b)
{
int temp = b;
b = a;
a = temp;
}
}
}
이에 따른 결과는 이렇습니다.
교환 전: a=40, b=10 <br>
교환 후: a=10, b=40 <br>
아까 전의 예제와 비교해보았을 때 ref라는 키워드를 추가로 등장시켰는데, 이것은 매개변수를 참조형식으로 이용할 때 사용됩니다.
메소드의 선언과 호출때 ref키워드를 달아주면 Call by reference형식으로 넘겨줍니다.
따라서 결과로 a와 b값이 서로 바뀌었으며, 원본의 데이터 값이 바뀌었습니다.
이는 아마 게임을 코딩할 때 같은 물건의 아이템의 물건을 나눌때 이용해보지 않을까 싶네요..ㅎㅎ
3. 메소드 오버로딩 (Method Overloading)
메소드 오버로딩이라는 개념을 처음 봤는데, 이는 메소드명을 중복하여 다르게 구현하는 것을 의미합니다.
C에서는 이게 불가능하는데, C#에서는 이것이 가능합니다~!!
같은 메소드명에서 인자만 다르게 하여 매개변수의 데이터 형식, 수에 따른 코드를 실행할 수 있습니다.
예를 보겠습니다.
..
static int Add(int a, int b) {
Console.WriteLine("두 int형 끼리의 덧셈");
return a + b;
}
static int Add(double a, double b) {
Console.WriteLine("두 double형 끼리의 덧셈");
return a + b;
}
static int Add(int a, int b, int c) {
Console.WriteLine("세 int형 끼리의 덧셈");
return a + b + c;
}
..
여기서 같은 메소드인데도 여러 번 이용할 수 있습니다. 매개변수에 따라 호출되는 메소드가 다르기 때문입니다.
오버로딩을 활용한 예제를 만들어보겠습니다.
using System;
namespace Study
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("{0}", Add(50, 10));
Console.WriteLine("{0}", Add(544.2, 63.2));
Console.WriteLine("{0}", Add(4, 7, 9));
}
static int Add(int a, int b)
{
Console.WriteLine("두 int형 끼리의 덧셈");
return a + b;
}
static double Add(double a, double b)
{
Console.WriteLine("두 double형 끼리의 덧셈");
return a + b;
}
static int Add(int a, int b, int c)
{
Console.WriteLine("세 int형 끼리의 덧셈");
return a + b + c;
}
}
}
결과는 이렇습니다.
두 int형 끼리의 덧셈 <br>
60 <br>
두 double형 끼리의 덧셈 <br>
607.4 <br>
세 int형 끼리의 덧셈 <br>
20 <br>
여기서의 예제도 Add라는 메소드로 다른 형태의 값들을 전달하였는데 결과를 보면 제대로 출력되는 것을 확인할 수 있습니다.
이처럼 매개변수의 형식과 수에 따라 메소드가 호출되는 것이 다르다는 것을 확인할 수 있습니다. C와는 다른 특이한 장점이라고 볼 수 있겠네요.
자, 여기까지가 기본 개념이고, 방금 전 예제를 이용해서 등장한 키워드에 대해서 자세하게 알아보겠습니다!!
4-1. ref
Call by reference 예제에서 나왔습니다. 이 역할을 다시 정리하자면, 변수의 값을 그대로 전달하는게 아니라
변수의 메모리 주소를 전달한다고 생각하면 됩니다.
이를 이용한 예제를 하나 더 만들어보겠습니다.
using System;
namespace Study
{
class Program
{
static void Main(string[] args)
{
int a = 40;
Add(ref a, 100);
Console.WriteLine("a={0}", a);
Add(ref a, 200);
Console.WriteLine("a={0}", a);
Add(ref a, 300);
Console.WriteLine("a={0}", a);
}
static void Add(ref int a, int b)
{
a += b; // a = a + b;
}
}
}
결과는
a=140 a=340 a=640
으로 나옵니다.
코드를 보면, ref키워드가 메소드를 호출할때도 쓰이고 매개변수에도 쓰였습니다. Add 메소드의 매개변수에 변수 a의 주소값을 넘겨줬습니다.
그리고 실질적인 a의 주소를 안 Add메소드는 a에다 매개변수 b의 값을 a에 더합니다. 결과적으로 덧셈이 진행되었다는 것을 확인하였습니다.
ref매개변수를 활용할때는 메소드를 호출할때, 정의할때 이 키워드를 명시적으로 사용해줘야 됩니다.
4-2. out
out키워드는 ref키워드와 비슷하게 인수를 참조로 전달할 때 사용하는데, ref키워드와는 달리 초기화를 딱히 하지 않아도 전달을 할 수 있습니다.
이를 이용하여 예제를 만들어보겠습니다.
using System;
namespace Study
{
class Program
{
static void Main(string[] args)
{
int a;
Add(out a);
Console.WriteLine("a={0}", a);
}
static void Add(out int a)
{
a = 100;
}
}
}
이에 따른 결과로 a=100이 나옵니다.
ref보다 코드가 매우 간단한데, 여기서는 Add메소드가 등장하고 매개변수로 변수 a의 주소값을 바로 넘깁니다.
그러면 이 주소값을 이용하여 a에 접근하고 바로 100이라는 값을 대입합니다.
여기서 a의 값은 100이 됩니다. 메소드를 빠져나온 후 a의 값을 출력해보면 결과가 100이 되는 것을 확인할 수 있습니다.
4-3. params
이 키워드는 우리가 길이에 제한을 받지않고 수를 넘겨준 후 총 합을 구하고 싶을때 이용합니다.
이 기능은 메소드에 여러 개의 값을 전달할 수 있도록 도와줍니다.
예제를 만들어 보겠습니다.
using System;
namespace Study
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("sum={0}", total(20, 10, 40, 4, 7, 6, 44, 55, 2));
Console.WriteLine("sum={0}", total(30, 4, 5));
}
static int total(params int[] list)
{
int sum = 0;
for (int i = 0; i < list.Length; i++)
sum += list[i];
return sum;
}
}
}
이 코드에서는 값 여러 개를 total 메소드에 넘겨주는데, total 메소드를 볼때 매개변수에 params 키워드를 이용하고 int형 뒤에 []가 붙었습니다.
여기서 params는 키워드가 아닌 배열이란 개념을 이용하였다는 것을 알 수 있습니다.
배열은 전에 설명했듯이, 변수들이 줄지어 있는 것과 같다고 보시면 됩니다.
따라서 int[]는 정수형 배열이라는 것을 알 수 있습니다. 그리고 total 메소드로 20,10,40,7,6,44,55,2를 넘겼고, list는 이 배열을 저장합니다.
그리고 이 list를 가지고 하나하나 접근하면서 sum이란 변수에 더하고 반복문을 빠져나와 sum의 값을 return을 사용하여 반환합니다.
for문을 살펴보면, list.Length는 배열 list의 길이를 구해주는 역할을 합니다. 그리고 list[i]처럼 배열에 있는 각 요소에 접근할 때 첨자값 (index)으로 접근합니다.
결론적으로는, params키워드는 매개변수의 길이를 제한없이 유연하게 해준다는 것을 알 수 있습니다.
마무리하며
오늘은 C언어에서의 함수와 같은 메소드를 배워보았습니다. 내용이 조금 많아서 난잡하게 느껴질 수도 있었을 것 같네요..
다음 시간에는 배열에 대해서 배우도록 하겠습니다!!
Comments