"눈이 나쁘면 안경을 쓴댔으니 모자란 너에겐 모자를 씌워주마" – 김케장 / 동전주머니엔 동전이 들었지

20130618
같은 타입의 클래스 간의 private 멤버 접근

보통 private 하면 자기 자신만 접근할 수 있고 다른 인스턴스들은 접근을 못 한다고 알고 있던 어느 날.

#include <iostream>

class ABC {
public:
    ABC() { a = 0; }
    ~ABC() {}

    void Func()
    {
        ABC abc;
        abc.a = 1; // private 멤버 접근
        abc.Func2(); // private 멤버 접근
    }

private:
    void Func2()
    {
        a = 2;
    }

    int a;
};

int main()
{
    ABC def;
    def.Func();

    return 0;
}

(설명을 위해 간단히 적음.)

클래스 멤버의 접근 제어를 수정하다가 중간에 주석 있는 줄과 같은 상황의 코드를 보게 되는데, 에러가 안 납니다. (abc.a에 1 들어간 후 2 들어감.)

뭐 시 라 ?
뭐 시 라 ?

프로그래밍이라는 걸 시작하고 5년간 알고 있던 사실이 한순간에 날아가면서 혼란 돌입. c#에서 작업하고 있어서 “아하, c#은 원래 그렇구나. 우훗”하면서 얘만 그런가 보다 하다 혹시나 해서 cpp에서 해보니 에러 없이 똑같이 잘 됩니다. 뭐..뭐시라? 집에 있는 cpp 책들 전부 꺼내서 해당 부분 설명을 다시 보기 시작.

Beginning Visual C++ 6 초판(1999)

407p ‘일반적으로, private인 클래스 멤버들은 클래스의 멤버 함수에 의해서만이 엑세스될 수 있다. 단, 우리가 나중에 생각해 볼 그 외의 한 가지 경우가 있다. 보통의 함수는 클래스의 private 멤버를 엑세스할 수 있는 직접적인 수단을 가지지 않는다.’

열혈강의 C++ 프로그래밍 1판(2004)

108p ‘일단 private이 의미하는 바부터 이야기하겠다. private으로 멤버가 선언이 되면 클래스의 내부 접근만 허용하겠다는 의미가 된다. 따라서 멤버가 private으로 선언이 되었음에도 불구하고 외부 접근을 시도한다면 컴파일러는 에러를 발생시킬 것이다.’

C++ 기초 플러스 5판(2006)

568p ‘그러나 프로그램은 public 멤버 함수를 통해서만(또는 11장, “클래스의 활용”에서 설명하는 프렌드 함수를 통해서만) 그 객체의 private 멤버에 접근 할 수 있다.’

C++ 프라이머 4판(2007)

111p ‘접근 권한(access labels): 클래스 멤버를 private로 정의하면 그 타입을 사용하는 코드에서 멤버에 접근하는 것을 막는다.’

혼자 연구하는 C/C++ 2권 와우북스 초판(2009)

47p ‘이 속성을 가지는 멤버는 외부에서 엑세스할 수 없으며 구조체의 멤버 함수만 엑세스할 수 있다. 외부에서는 프라이비트 멤버를 읽을 수 없음은 물론이고 존재 자체도 알려지지 않는다.’

공통으로 private 멤버는 멤버 함수(와 프렌드)에서만 사용할 수 있으며 외부에서는 접근이 안 된다고 설명하고 있습니다. 맞는 말입니다. 그런데 다시 맨 위의 코드로 돌아가서 봅시다. 메인 함수에서 ABC 타입의 클래스 def를 생성하고 멤버 함수 Func를 호출합니다. def의 멤버 함수 Func에서는 ABC 타입의 클래스 abc를 만들어서 private 멤버인 변수 a와 함수 Func2에 접근하고 있습니다. 위에 책들 설명대로 보자면 private 변수, 함수에 접근하려면 abc의 멤버 함수, 즉 abc.Func() 내부에서만 접근할 수 있으며, 현재 있는 곳은 def.Func() 내부이기 때문에 컴파일 에러가 나야 합니다. 그런데 그것이 실제로 일어나지 않았습니다. 에러가 안 납니다. 잘되네요.

이쯤에서 사놓고 세 번 열어본(이제 네 번) 비야네 스트롭스트룹 선생님의 The C++ Programming Language를 봅시다. 여기서도 ‘· private : 이 멤버가 선언된 클래스의 멤버 함수 및 그 클래스의 프렌드만 이 멤버의 이름을 사용 할 수 있다.’라고 적혀 있습니다. 뭐 당연하겠지만 같은 얘기를 하고 있네요.

책 설명도 저런데 지금 위에 코드가 왜 에러가 나지 않느냐면 private 설명에 빠진(건지 책에 있는데 못 본 건지 모르겠지만) 부분이 있어서 그렇습니다. 빠진 부분이라는 건 접근 제한은 인스턴스 단위가 아니라, 클래스 단위라는 것입니다. 다시 말해서 위에 코드에서처럼 어떤 클래스의 멤버 함수 내부에서 같은 타입의 다른 인스턴스의 private 멤버 접근이 가능하다는 이야기입니다. 이 설명이 빠져서 오해의 소지가 좀 있기는 한데 이해하는데 있어서 외부, 내부만 생각하다 보니(책 설명도 보기에 따라 다르고) 이렇게 된 것 같네요. 외부, 내부만 놓고 보면 아주 이상한 코드지만 위에 설명대로 클래스(인스턴스가 아니라 클래스 정의)의 멤버 함수 내에서 클래스의 멤버 변수에 접근하는 경우이기 때문에 가능합니다. (클래스가 내용을 이미 알고 있어서 비밀이 비밀이 아니라고 생각해도 될 듯하네요.)


참고

위에 나열한 책들
http://kldp.org/node/55796
http://kldp.org/node/115611
http://msdn.microsoft.com/en-us/library/zsc61976(v=vs.80).aspx
http://stackoverflow.com/questions/12355372/private-member-accessible-from-other-instances-of-the-same-class

댓글이 3개 우앙 | 타닥타닥

  1. 감사합니다. 저도 연산자 오버로딩 공부하다가 문득 에러가 안나길래 찾아봤습니다. 좋은 정보 감사합니다.

  2. 복사생성자 공부하면서 Simple(Simple &copy) : num1(copy.num1) {} 에서 copy.num1처럼 같은 클래스지만 다른 객체의 private에 접근할 수 있길래, 궁금증이 생겼었는데 감사합니다.

  3. 중간의 짤 ‘뭐 시 라?!’ 에 웃고갑니다 ㅋㅋㅋ 마침 궁금증을 검색하다가 들렀어요~

댓글 남기기

* 표시된 곳은 반드시 입력해주세요