C++0x 미리보기 6, 확장된 friend 선언

Twitter icon류광, 2008-04-01 19:04
friend가 좀 더 유용해집니다.

class X1 { friend C; // (1) };

class X2 { friend Ct; // (2) };

template class R { friend T; // (3) };

(1) 현재 C++에서 다른 클래스를 친구로 삼는 경우 반드시 class 키워드를 붙여서 friend class C;라고 해야 합니다. 그러나 이 경우 C가 클래스임을 이미 컴파일러도 알고 있으므로 class를 꼭 써줘야 하는 것은 불필요한 제약이라고 할 수 있습니다. struct나 union도 마찬가지입니다.

(2) 현재 C++에서는 typedef로 정의된 형식 이름을 friend 선언에 사용할 수 없습니다. 다른 대부분의 경우에는 원 클래스 이름과 typedef된 이름을 차별 없이 사용할 수 있다는 점에서 역시 불필요한 제약입니다.

(3) 현재 C++에서는 템플릿 인수를 친구로 삼을 수가 없습니다. 

이러한 제약들이 생긴 이유는 [N1520](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1520.pdf)의 II. History에 나와 있는데, 아주 간단하게 이야기하면 다른 어떤 문제를 해결하기 위한 제약이 friend에까지 번졌던 것이라고 보면 될 것 같습니다. 어쨌든, 이 제안에 의해 위의 세 가지 제약을 모두 제거됩니다.

(1)에 대해 한 가지 부연 설명을 하자면, 이 제안이 적용된다고 해도 class 키워드를 반드시 붙여야 하는 경우가 여전히 남아 있습니다. 다음 예처럼 아직 존재하지 않은 클래스를 친구로 선언하는 경우입니다.

class C; class X1 { friend C; // 기존 클래스를 친구로 선언 friend class D; // 새로운 클래스를 선언함과 동시에 //이 클래스의 친구로 선언. 이 // 경우에는 class 키워드가 필수임. };


(3)과 관련해서는, 템플릿 인수를 친구로 삼을 수 있으면 여러 가지 재미있는 기법이 가능해 집니다. 예를 들어 Java의 final 클래스처럼 상속이 불가능한 C++ 클래스를 만들고 싶다고 합시다. 현재 가능한 방법은 생성자가 private인 부모 클래스를 상속하고, 그 부모 클래스가 자식 클래스를 친구로 선언하는 것입니다. 다음은 Bjarne Stroustrup이 제시한 코드입니다(<http://www.research.att.com/~bs/bs_faq2.html#no-derivation>)

class Usable;

class Usable_lock { friend class Usable; private: Usable_lock() {} Usable_lock(const Usable_lock&) {} };

class Usable : public virtual Usable_lock { // ... public: Usable(); Usable(char*); // ... };

Usable a;

class DD : public Usable { };

DD dd; // 오류: DD::DD()에 접근할 수 없음 // Usable과는 달리 DD는 Usable_lock의 // 친구가 아니므로 Usable_lock::Usable_lock()에 // 접근할 수 없다.

그런데 Usable_lock은 Usable만 알고 있으므로, 또 다른 상속 금지 클래스를 만들기 위해서는 Usable_lock과 본질적으로 동일한 부모 클래스를 만들거나 Usable_lock에 또 다른 friend 선언을 추가해야 합니다. 매번 그런 일을 하는 것은 비합리적이므로 당연히 템플릿을 떠올리게 됩니다.

template class Non_derivable { friend T; // !! 현재는 불가능 !! private: Non_derivable() {} Non_derivable(const Non_derivable&) {} };

위의 템플릿 클래스가 컴파일된다면(즉 템플릿 친구 선언이 허용된다면) 다음 예와 같이 좀 더 쉽게 상속 금지 클래스들을 만들 수 있습니다.

class Foo : public Non_derivable { // ... };

class Bar : public Non_derivable { // ... 마찬가지 ... };



마지막으로 friend 자체에 대한 이야기 하나를 덧붙이자면, friend가 OOP의 캡슐화나 정보 은폐를 해친다는 주장이 있는데 그렇지 않습니다. 많은 경우 friend는 public 멤버의 개수를 줄여주며, 당연한 말이겠지만 public 멤버가 적을수록 캡슐화가 좋아집니다. friend를 피하기 위해 인위적으로 public 멤버를 추가한다면 그것이 더 해가 되지요.
태그: 프로그래밍 C++ C++0x

comments powered by Disqus

예전 댓글(읽기 전용)