C# 프로그래밍 10번째 시간 - 클래스와 접근 제한자

유니티의 열걸음, C# 공부시작 42일차

오늘은 클래스(Class)와 접근 제한자(Access Modifier)에 대해서 배우겠습니다!
클래스는 매우 중요한 부분이라 “조각지식모음”에 다루려고 하였지만 메인 공부에 넣었고,
클래스에 대해서 배우고 난 후 접근 제한자에 대한 내용도 알아야되서 함께 넣었습니다! 시작하겠습니다!

1. 객체

먼저 클래스에 대해서 배우기 전에, 객체 지향(Object Oriented Programming)을 알아야 됩니다.
C#은 객체 지향 언어이고, JAVA도 마찬가지입니다. 객체(Object)는 매우 중요한 부분이라 먼저 다루겠습니다.

객체를 영어 Object라고 하는 것처럼 물체, 물건을 의미합니다. 모니터, 마우스, 키보드…등등 개념상으로
존재하는 것은 모두 객체입니다. 어떤 내용과 정보들도 다 객체에 속합니다.

github

모든 객체들은 상태(state)와 행동(behavior) 을 지니고 있고 이를 표현할 수 있습니다.
어떤 상태이고 이를 이용하여 어떤 행동을 하는 것을 의미합니다.
예를 들어 전화기라면, 전화기의 색은 상태이고 전화기로 전화걸고 끊는 동작은 행동입니다.
자동차는 속도를 상태라고 한다면 속도를 올리거나 줄이거나 멈추는 것이 다 행동입니다.

C#프로그래밍에서는 상태를 데이터(변수)로 두고, 행동을 메소드로 표현을 합니다.
따라서 C#에서는 객체가 데이터와 메소드로 이루어진 것입니다.
프로그래밍의 객체는 붕어빵 틀로 예시를 드는데, 틀을 클래스라고 한다면 틀을 찍어서 붕어빵을
만드는 행위를 클래스라고 합니다. 틀(클래스)이 하나만 있어도 붕어빵(객체)를 여러 개 찍어낼 수 있습니다!!

2. 클래스

객체를 어느정도 이해하였으면 클래스를 이해해봅시다! 클래스 선언형태는 이러합니다.

[접근 제한자] class 클래스명 
{
	// 필드, 메소드 ... 
}

여기서 접근제한자는 말 그대로 해당 클래스로 접근하는 것을 제한할 때 사용합니다.
접근 제한자는 추후 상세하게 다루겠습니다!! 클래스에선 필드, 메소드가 있는데
상태필드(field)라고 부르고, 행동메소드(method)으로 부릅니다.

클래스는 어떤 것을 딱 정의를 하고 이에 대한 상태와 행동을 설명하고 초기화한다고 생각하면 됩니다.
예를 들어, 몬스터 하나를 두고 체력, 공격력, 방어력을 설명해보겠습니다.

.. 
class Monster 
{ 
	private string HP; // 몬스터의 체력을 나타내는 필드 
	private string ATK; // 몬스터의 공격력을 나타내는 필드
	private string DEF; // 몬스터의 방어력을 나타내는 필드
        private string name = "슬라임"; // 몬스터의 이름을 나타내는 필드
	
	public void Attack() // 몬스터가 공격을 하는 행동
	{ 
		Console.WriteLine("{0}이 공격을 시전하였습니다!", name); 
	}
} 
...

여기서 설명한다는 것을 추상화라고 부릅니다. 불필요한 부분은 과감히 없애고 중요한 부분을 중점에 두어 간략화 시키는 것을 의미합니다.
앞의 예시도 몬스터를 추상화하였다고 보면 됩니다. 이제 몬스터를 추상화한 코드를 이용하여 예제를 만들어보겠습니다.

[클래스를 이용한 예제 - 몬스터 추상화]

using System; 

namespace Study 
{ 
	class Monster
	{ 
		public string HP; // 몬스터의 체력을 나타내는 필드 
	        public string ATK; // 몬스터의 공격력을 나타내는 필드
	        public string DEF; // 몬스터의 방어력을 나타내는 필드
                public string name = "슬라임"; // 몬스터의 이름을 나타내는 필드
	
	        public void Attack() // 몬스터가 공격을 하는 행동
	        { 
	        	Console.WriteLine("{0}이 공격을 시전하였습니다!", name); 
	        }
		
	} 
	
	class Program 
	{ 
		static void Main(string[] args) 
		{ 
			Monster mon = new Monster(); 
			mon.HP = "1000"; 
			mon.ATK = "300"; 
			mon.DEF = "50"; 
			mon.Attack(); 
			Console.WriteLine("몬스터의 체력: {0}, 몬스터의 공격력: {1}, 몬스터의 방어력: {2}", mon.HP, mon.ATK, mon.DEF); 
		} 
	}
}

이에 따른 결과는 이렇습니다.

슬라임이 공격을 시전하였습니다! 
몬스터의 체력: 1000, 몬스터의 공격력: 300, 몬스터의 방어력: 50 

예제를 한번 뜯어보면, Monster라는 클래스가 등장한 후, 클래스 안에 몬스터의 체력,
공격력, 방어력, 이름을 나타내는 필드및 공격하는 행동을 취하는 메소드를 만들었습니다.
그리고 Program이라는 클래스 (메인 클래스 - 프로그램의 총 부분을 담당하는 클래스)에서 Monster이라는 틀로 mon이라는 객체를 만들었습니다.

또한 밑에서 멤버 변수의 값을 초기화한 것을 볼 수 있습니다. 그리고 mon 객체 안에 있는 Attack이라는 메소드를 호출하였고,
몬스터의 체력, 공격력, 방어력을 가져와서 출력하면서 프로그램을 마무리하였습니다.

여기서 중요한 부분은 바로 이 부분입니다.

Monster mon = new Monster();

new 키워드 뒤에 등장하는 Monster 클래스를 기반으로 mon이라는 객체를 만든다는 의미입니다.
마지막에 등장하는 Monster()를 생성자라고 하는데, 생성자는 접근 제한자, 소멸자, this와 같습니다.
이에 대해서 곧 자세하게 배우겠습니다. new 키워드를 이용한 객체 생성 방법은 이러합니다.

클래스명 식별자 = new 클래스명();

어떤가요? 이러니 게임 코딩에 조금 더 가까워진 기분이 들지 않나요? ㅎㅎ

3. 접근 제한자

접근제한자접근 범위를 결정하게 해주는 역할을 합니다. 가장 많이 본 것은 위에 예제로 나왔던 public, private일 겁니다.
이 접근 제한자 종류를 표로 정리해보겠습니다.

접근 제한자 설명
private 클래스 내부에서만 접근이 가능합니다.
public 모든 곳에서 해당 멤버로 접근이 가능합니다.
internal 같은 어셈블리에서만 public으로 접근이 가능합니다.
protected 클래스 외부에서 접근할 수 없으나 파생 클래스에서는 접근이 가능합니다.
protected internal 같은 어셈블리에서만 protected으로 접근이 가능합니다.

이를 이용하여 예를 들어보겠습니다. 우리는 A라는 클래스를 만들어보겠습니다.

class A

{
   int B;
   int C;
   ...
}

클래스 A에서 B와 C라는 멤버 변수가 존재합니다. A 클래스에 기반을 둔 객체를 생성하고 이 객체로 접근을 해보겠습니다!

A a = new A();

a.B = 1; // 보호 수준 에러!

이렇게 하면 에러가 발생합니다. 에러의 내용으로는 보호 수준으로 인해 액세스할 수 없다고 나옵니다.
클래스의 멤버를 접근 제한자로 수식하지 않으면 멤버의 보호 수준(접근 수준)은 무조건 private으로 지정되는데
private은 클래스 내부에만 접근 가능하기 때문에 이 수준을 public으로 지정해놔야 됩니다..

class A
{
    public int B;
    public int C;
    ...
}

이 형식으로 바꿔놓으니 에러가 생기지 않습니다. public모든 곳에서 이 멤버에 접근할 수 있게 만들어줍니다.
주로 사용하는 것은 보통 public과 private인데, 나머지에 대해서도 알아보겠습니다.
internal접근 수준이 지정되면 동일한 어셈블리(프로그램)에서만 접근할 수 있습니다.
다른 프로그램에서 참조, 접근하게 되면 오류가 발생합니다.

protected클래스 외부에서는 접근할 수 없지만 파생된 클래스에서는 접근할 수 있습니다!
예시를 보겠습니다.

namespace Study
{
	class A
	{
		protected int x = 123;
		
	}
	class B : A
	{
		static void Main()
		{
			A a = new A();
			B b = new B();
			// 에러 발생, 왜냐하면 X는 오직 A에서 파생된 클래스에서만 접근이 가능하기 때문
			a.x = 10;
			// A에서 파생된 클래스인 B에선 접근이 가능하다.
			b.x = 10;
		}
	}
}

A 클래스에서 접근 수준을 protected으로 지정해놓았기 때문에 B 클래스에서 x을 사용할 수 없습니다.
A.x 멤버에 접근하려면 B 클래스이거나, B 클래스로부터 파생된 클래스이어야 접근 할 수 있습니다!
그러나 A a = new A(); 이 부분을 없애면 B는 A로부터 파생되었기 때문에 정상적으로 실행이 가능합니다.
파생 클래스에 대해서도 추후에 더 다뤄보도록 하겠습니다!!

4. this

this키워드자기 자신을 가리킬 때 사용합니다. 먼저 예제를 만들어 보겠습니다.

using System;

namespace Study
{
	class A
	{
		private int num;
		public A(int num)
		{
			num = num;
			
		}
		public void Show()
		{
			Console.WriteLine("num: " + num);
		}
		
	}
	class Program
	{
		static void Main(string[] args)
		{
			A a = new A(50);
			a.Show();
		}
	}
}

이에 따른 결과로 num: 0 이 나옵니다.
앞에서 num = num; 이라는 코드가 보이는데 사실 앞num과 뒤num은 다릅니다.
이를 생성자와 소멸자라고 부르는데, 이는 다음시간에 자세하게 배우겠습니다!

간단히 알아보자면, 생성자객체를 생성하기 위한 것이고, 객체를 생성할 때 객체의 멤버 변수를 원하는 값으로 초기화할때 사용됩니다.
객체를 생성할 때 생성자가 한번 호출되는데, 여기서 num을 num 값으로 초기화합니다.
여기서는 객체의 멤버 변수인 num 값이 변한것이 아니라, 매개변수의 값이 변했다고 보시면 됩니다.
사실상 아무런 의미도 없는 코드라고 볼수도 있습니다.
또 객체를 생성할때 생성자에게 50이란 값을 넘겨주었는데, 결과를 보시면 num의 값은 변하지 않습니다.

조금 헷갈릴텐데 다음시간인 생성자와 소멸자에서 자세하게 배우겠습니다..

일단 매개변수 이름과 멤버 변수의 이름이 서로 같을때 멤버 변수 num을 수정하기 위해서
this 키워드를 사용합니다.. 이런 식으로 말이죠

...
public A(int num)
{
	this.num = num;
}
...

이처럼 this 키워드를 사용하면 클래스에서 정의한 멤버 변수인 num을 가르키게 됩니다.
정리하면 클래스에 정의한 멤버 변수 num에 매개변수 num의 값을 집어넣으라는 말과 같습니다.
이에 결과를 보면 정상적으로 출력이 됩니다.

마무리하며

오늘은 클래스와 접근제한자에 대해서 배웠는데, 사실 이에 파생되는 내용들이 많지만 글이 길어지기에 한번 끊었습니다! 다음 시간에는 생성자와 소멸자에 대해서 자세하게 배워보도록 하겠습니다!!

Categories:

Updated:

Comments