접근 제한자(Access Modifier)
오늘은 접근 범위를 결정하게 해주는 접근 제한자에 대해서 알아보려고 합니다. 접근 제한자에는 public, protected, internal, protected internal, private가 있습니다. 이미 public라는 접근 제한자는 본적이 있죠? 이 다섯가지의 접근 제한자에 대해 알아보려고 합니다. 아래는 5개의 접근 제한자를 정리해놓은 표입니다.
접근 제한자 | 설명 |
---|---|
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는 클래스 외부에서는 접근할수 없지만 파생된 클래스에서 접근할 수 있는 특징을 가지고 있습니다.
using System; using System.Collections.Generic; using System.Linq; using System.Text; 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에 있던 예제를 가져온 것입니다. 10줄을 보시면 접근 수준이 protected로 지정되었죠? 이것을 컴파일하면 어떤일이 벌어질까요? 컴파일 시에는 다음과 같은 오류가 발생합니다.
오류 1 'ConsoleApplication1.A' 형식의 한정자를 통해 보호된 'ConsoleApplication1.A.x' 멤버에 액세스할 수 없습니다. 한정자는 'ConsoleApplication1.B' 형식이거나 여기에서 파생된 형식이어야 합니다. C:\Users\su6net\documents\visual studio 2019\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs 21 15 ConsoleApplication1
오류를 살펴보자면 즉, A.x 멤버에 접근하려면 클래스 내부에서 접근하거나, 이 클래스로부터 파생된 클래스여야 접근이 가능하다는 것을 말하고 있습니다. 그렇다면 21줄에 있는 코드를 주석처리 하고 컴파일하게 되면, 아무런 오류없이 컴파일 되는것을 확인할 수 있습니다. 24줄에 있는 코드는 아무런 문제없이 접근이 가능하죠.
파생 클래스에 대해서는 나중에 다시한번 살펴볼것인데, 우선은 한정자마다 접근할 수 있는 범위가 어떠한지만 기억해두시면 됩니다.
this
this 키워드는 자기 자신을 가리킬때 사용하는 키워드입니다. this 키워드가 어떠한 역할을 하는지 예제를 통해 살펴보도록 합시다.
using System; using System.Collections.Generic; using System.Linq; using System.Text; 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 계속하려면 아무 키나 누르십시오 . . .
코드를 보니 처음 접하는게 있죠? 바로 12~14행을 보니 클래스의 이름과 똑같은 이름을 가진 메소드가 보입니다. 이를 생성자라고 하며, 다음 강좌에서 소멸자와 같이 배우게 될 부분입니다. 간단히 알아보자면, 생성자는 객체를 생성하기 위해 존재하며, 객체를 생성할 때 객체의 멤버 변수를 원하는 값으로 초기화 하고 싶을때 주로 사용됩니다. 객체를 생성할 때 생성자가 한번 호출되는데, 13행을 보시면 num을 num 값으로 초기화 시키고 있습니다. 말이 좀 애매한데, 여기선 객체의 멤버 변수인 num 값이 변한것이 아니라, 매개변수의 값이 변했다고 보시면 됩니다. 아무런 의미도 없는 코드죠. 26행에서 객체를 생성할때 생성자에게 50이란 값을 넘겨주었는데, 결과를 보시면 num의 값은 변하지 않습니다.
그렇다면, 매개변수 이름과 멤버 변수의 이름이 서로 같을때 멤버 변수 num의 값을 수정하려면 어떻게 해야 할까요? 바로 this 키워드를 사용하시면 됩니다. 아래와 같이 바꿔주시면 되겠죠?
... public A(int num) { this.num = num; } ...
여기서 this 키워드를 사용하면 클래스 내에 정의한 멤버 변수 num을 가르키게 됩니다. 즉, 클래스 내에 정의한 멤버 변수 num에 매개변수 num의 값을 집어넣으라는 말과 같습니다. 다시 결과를 보시면 정상적인 값을 출력하고 있음을 확인할 수 있습니다.