Media Log


1. 접근 제한자(Access Modifier)


오늘은 접근 범위를 결정하게 해주는 접근 제한자에 대해서 알아보려고 합니다. 접근 제한자에는 public, protected, internal, private가 있습니다. 이미 public라는 접근 제한자는 본적이 있죠? 이 네 가지의 접근 제한자에 대해 알아보려고 합니다. 아래는 4개의 접근 제한자를 정리해놓은 표입니다.


접근 제한자

설명 

private

클래스 내부에서만 접근이 가능합니다.

public 

모든 곳에서 해당 멤버로 접근이 가능합니다.

internal

같은 어셈블리에서만 public으로 접근이 가능합니다. 

protected

클래스 외부에서 접근할 수 없으나 파생 클래스에서는 접근이 가능합니다.

protected internal 

같은 어셈블리에서만 protected으로 접근이 가능합니다. 


이해를 돕기위해 예를 하나 들겠습니다. 예를 들어, 다음과 같은 클래스가 있다고 가정해봅시다.

class A

{

  int B;

  int C;

  ...

}

클래스 A 내에 B와 C라는 멤버 변수가 존재합니다. 그럼 이제 한번, A 클래스에 기반을 둔 객체를 생성하고 이 객체로 접근을 해보도록 하겠습니다.

A a = new A();

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

그런데, 컴파일을 하자마자 에러가 발생했습니다. 에러를 확인해보니, 다음과 같은 이유로 컴파일을 할 수 없다는 것이였습니다.


오류 1 보호 수준 때문에 'ConsoleApplication1.A.B'에 액세스할 수 없습니다. C:\Users\su6net\AppData\Local\Temporary Projects\ConsoleApplication1\Program.cs 20 15 ConsoleApplication1


그 이유가 무엇일까요? 클래스의 멤버를 접근 제한자로 수식하지 않으면 멤버의 보호 수준(접근 수준)은 무조건 private로 자동으로 지정이 됩니다. private로 지정되면 클래스 내부에서만 접근이 가능하다는것은 이미 위의 표에서 보았습니다. 즉, 외부에서는 접근할 수 없으니 접근이 가능하게 멤버의 접근 수준을 public로 지정해봅시다.
class A
{
   public int B;
   public int C;
   ...
}
그랬더니, 더는 보호 수준 에러가 보이지 않았습니다. public으로 지정하게 되면, 모든 곳에서 이 멤버에 접근할 수 있게 되니 말이죠. 그럼 internal과 protected는 뭘까요? internal로 접근 수준이 지정되면 동일한 어셈블리, 즉 동일한 프로그램에서만 접근할 수 있습니다. 만약 어셈블리 외부에서 참조하게 되면 당연히 오류가 발생합니다.

protected는 클래스 외부에서는 접근할수 없지만 파생된 클래스에서 접근할 수 있는 특징을 가지고 있습니다.
namespace ConsoleApplication1
{
    class A
    {
        protected int x = 123;
    }

    class B : A
    {
        static void Main()
        {
            A a = new A();
            B b = new B();

            // 에러 CS1540 발생, 왜냐하면 X는 오직 A에서 파생된 클래스에서만 접근이 가능하기 때문
            a.x = 10;

            // A에서 파생된 클래스인 B에선 접근이 가능하다.
            b.x = 10;
        }
    }
}
위의 protected 관련 예제는 MSDN에 있던 예제를 가져온 것입니다. 5줄을 보시면 접근 수준이 protected로 지정되었죠? 이것을 컴파일하면 어떤일이 벌어질까요? 컴파일 시에는 다음과 같은 오류가 발생합니다.

오류 1 'ConsoleApplication1.A' 형식의 한정자를 통해 보호된 'ConsoleApplication1.A.x' 멤버에 액세스할 수 없습니다. 한정자는 'ConsoleApplication1.B' 형식이거나 여기에서 파생된 형식이어야 합니다. C:\Users\su6net\documents\visual studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs 21 15 ConsoleApplication1

오류를 살펴보자면 즉, 'A.x 멤버에 접근하려면 B 클래스이거나, B 클래스로부터 파생된 클래스여야 접근이 가능하다'는 것을 말하고 있습니다. 그렇다면 16줄에 있는 코드를 주석처리 하고 컴파일하게 되면, 아무런 오류없이 컴파일 되는것을 확인할 수 있습니다. 19줄에 있는 코드는 아무런 문제없이 접근이 가능하죠. 

파생 클래스에 대해서는 나중에 다시 한번 살펴볼 것인데, 우선은 한정자마다 접근할 수 있는 범위가 어떠한지만 기억해두시면 됩니다.

2. this

this 키워드는 자기 자신을 가리킬때 사용하는 키워드입니다. this 키워드가 어떠한 역할을 하는지 예제를 통해 살펴보도록 합시다.
using System;

namespace ConsoleApplication1
{
    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
계속하려면 아무 키나 누르십시오 . . .

코드를 보니 처음 접하는게 있죠? 바로 9~12행을 보니 클래스의 이름과 똑같은 이름을 가진 메소드가 보입니다. 이를 생성자라고 하며, 다음 강좌에서 소멸자와 같이 배우게 될 녀석입니다.

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

그렇다면, 매개변수 이름과 멤버 변수의 이름이 서로 같을때 멤버 변수 num의 값을 수정하려면 어떻게 해야 할까요? 바로 this 키워드를 사용하시면 됩니다. 아래와 같이 바꿔주시면 되겠죠?
...
public A(int num)
{
     this.num = num; 
}
...
여기서 this 키워드를 사용하면 클래스 내에 정의한 멤버 변수 num을 가르키게 됩니다. 즉, 클래스 내에 정의한 멤버 변수 num에 매개변수 num의 값을 집어넣으라는 말과 같습니다. 다시 결과를 보시면 정상적인 값을 출력하고 있음을 확인할 수 있습니다.

이번 강좌는 여기서 마무리 짓도록 하겠습니다. 수고하셨습니다.

다음 강좌에서는 생성자, 소멸자에 대해서 배워보도록 하겠습니다.

  1. 김승현 at 2012.10.20 13:47 신고 [edit/del]

    감사합니다~

    Reply
  2. 질문 at 2012.11.05 17:49 신고 [edit/del]

    안녕하세요, 시간날때마다 들어와서 배우고 갑니다.
    위에 보면 Class B 안의 main()에서 B b = new B(); 로 다시 B를 생성하는데요,
    B를 정의해서 만들고 있는데, 그 안에서 B를 생성할 수 있다는게 이해가 안되네요.
    자세한 설명 부탁드려요.

    Reply
    • BlogIcon EXYNOA at 2012.11.06 19:03 신고 [edit/del]

      그 클래스가 존재하기만 한다면, 그 클래스의 객체를 어디서나 만들 수 있습니다.

      이는 C#에서 지원하는 부분이며, 만약 B 클래스 내에서 B 객체를 만들 경우에는 그 B 객체가 만들어진 메소드를 제외한 나머지 메소드나 필드는 그 객체로 접근할 수 있습니다.

  3. ZiNee at 2013.10.15 11:11 신고 [edit/del]

    아직까진 이해 잘 됩니다. 계속해서 정주행 하겠습니다.

    Reply
  4. GB at 2018.02.06 15:42 신고 [edit/del]

    C나 C++ 관련 기본지식 없이 바로 C#공부중인데 몇번씩 보면 하나 이해가 되고 그러네요~ 잘보고 있습니다.

    Reply

submit

티스토리 툴바