2019년 2월 27일 수요일

[컴개실 최종보고서 4] 클래스와 메소드


4. 클래스와 메소드
1. 메소드
C나 C++ 언어에서 부르는 방식에선 함수라고 부르는 메소드는 간단히 말하면 매개 변수를 통해 Input을 넣었을 때, 일련의 작업을 수행하여 Output을 내놓는, 말 그대로 함수이다. 다음은 메소드를 선언하는 형식이다.

class 클래스의_이름
    {
        한정자 반환_형식 메소드의_이름( 매개_변수_목록 )
        {
            실행하고자_하는_코드;
            return 메소드의_결과;
        }

    }

한정자는 이 메소드가 이 클래스 외부에서도 쓰일 수 있는지를 결정짓는다. 외부에서 쓰일 수 있도록 하려면 한정자를 public으로 잡으면 된다. 반환 형식은 함수가 Output으로 내놓는 값의 데이터 형식이 어떤 것인지를 결정짓는다. 만약 Output으로 내놓고자 하는 것이 정수형이면, 반환 형식을 int로 잡으면 된다. 메소드의 이름은 말 그대로 개발자가 임의로 결정하는 메소드의 이름이다. 그 옆의 괄호에는 매개 변수의 목록이 자리잡게 되는데, 이는 메소드를 호출하면서 동시에 메소드에게 전달하는 Input 값들의 목록이다. 그 아래에는 메소드를 호출했을 때 실행하게 될 코드가 있고, return이라는 것이 자리잡고 있다. return 옆에 오는 값은 메소드가 Output으로 내놓는 값이다. 아래는 이에 대한 예시이다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HelloWorld
{
    class Test
    {
        public static int Add(int a, int b)
        {
           return a + b;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
           Console.WriteLine(Test.Add(3, 4));
        }
    }

}

우선 클래스 Test가 새로 선언되고, 그 안에는 외부에서도 쓰일 수 있으며, static으로 한정되고, 정수형 값을 Input으로 받는 메소드 Add가 선언된다. Add는 Input으로 받은 정수를 더한 값을 return 값으로 내보내며, Main 메소드에서는 3과 4를 Input으로 집어넣은 Add 메소드의 return 값을 콘솔 창에 출력한다. 이때, 눈 여겨봐야 할 것이 바로 Main 메소드에서 Test의 Add 메소드를 호출하는 방식인데, static 한정자를 가진 메소드의 경우,
클래스_이름.메소드_이름( 매개변수 )
의 형식으로 호출해야 한다.
static 한정자를 가지지 않은 메소드의 경우는 클래스를 다룰 때 살펴 본다.
한 가지 알아 두어야 할 점은, 매개 변수를 아무리 메소드 안에서 수정한다고 해도 메소드의 작업이 끝나게 되면 그 수정된 값은 남아있지 않고 원래대로 돌아가게 된다는 것이다. 이는 메소드에서 매개 변수의 값을 ‘복사’하여 다른 메모리에 저장한 뒤 그 값을 쓰게 되기 때문인데, 만약 메소드 안에서 매개 변수를 수정할 수 있도록 변경하려면 매개 변수 앞에 ref를 붙이면 된다.
2. 클래스
우리는 여태까지 이런 형식의 변수 선언을 많이 봐 왔다.
int a = 0;
우리는 int를 데이터 타입이라고 불러 왔으나, 여기서는 int를 ‘클래스’라고 부를 것이다. int라는 클래스는 a라는 ‘객체’가 어떠한 데이터를 담을 것인지를 알려주는 ‘청사진’이 되어주는 역할을 한다. 우리가 칼을 만들려고 할 때, 쇳물을 붓는 거푸집을 클래스라고 한다면, 거기에서 굳어서 나온 실제 칼을 객체라고 하는 것이다. 이를 예제를 통해 더 살펴보도록 하자.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HelloWorld
{
    class Student
    {
public string Name;

        public void Print()
        {
           Console.WriteLine(Name);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
           Student kim = new Student(); //1
           kim.Name = Kim Ku;
           kim.Print();
        }
    }

}

여기서는 클래스 Student가 선언되었다. 그 안에는 string 타입 변수 Name이 선언되었고, Name을 콘솔 창에 출력하는 메소드 Print가 선언되었다. 저번과 다른 점은 메소드에 static 한정자가 붙지 않았다는 것이다.
그리고 Main 메소드 중 오른쪽에 //1 이라고 쓰여 있는 부분에서Student 클래스의 형태를 띤 변수 kim에 대한 메모리 할당이 이뤄진다. 그 후 kim 안의 내용물을 수정하는데, kim의 이름을 Kim Ku로 바꿔 버리는 것이다. 다음에는 Print 메소드가 쓰이는데, 저번과는 다르게 클래스 이름 뒤에 .Print()를 붙이지 않고 변수 kim의 뒤에 .Print()를 붙인다. 이는 static 한정자가 메소드에 붙지 않았기 때문이다. 메소드가 철저하게 개인화된다.
만약 Student라는 클래스가 생성될 때부터 아예 Name까지 정해지도록 하고 싶다면 어떻게 해야 할까? 다음 코드를 보자.

namespace HelloWorld
{
    class Student
    {
public string Name;

        public void Print()
        {
           Console.WriteLine(Name);
        }

        public Student (string name)
        {
           Name = name;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
           Student kim = new Student(Kim Ku); //1
kim.Print();
        }
    }

}

여기서 무엇이 바뀌었는지 보자. public Student라고 쓰인 파트가 추가되었다. 옆의 괄호 안에는 매개 변수 같이 생긴 것이 있고, 중괄호 안에서는 Name에 매개 변수로 받은 string 변수 name을 대입하는 코드가 있다. 다음과 같이 써 주면, Main 메소드에서 Student kim을 새로 선언할 때, 괄호 안에 학생의 이름을 같이 써 주면 kim.Name에 따로 string 변수를 대입해주지 않더라도 Name에 “Kim Ku”라는 이름을 저장할 수 있다.
그리고 이러한 public Student(…)를 클래스 내에 여러 개를 설정할 수 있는데, 이때 괄호 안에 오는 매개 변수의 타입이 이미 클래스 내에서 설정된 public Student(…)와는 달라야 한다.