프렌드(friend)는 접근을 허락해 주는 키워드 이다. 이 프렌드(friend)선언의 특징 중 다음 두가지 이유 때문에 템플릿과 섞이면서 좀 복잡해 진다.

  1. 프렌드(friend)는 프렌드로 적용할 타입이 있을 때만 선언 할 수 있다.
  2. 프렌드(friend) 함수 선언이 함수의 정의가 될 수 있다.


프렌드 클래스 선언은 정의가 될 수 없으므로 걱정할 것이 없다. 1번에 의해서 다음 문법들만 성립 된다.

g++43 과 msvc9 에서 각각 돌려보면, 에러가 차이가 있다. 원칙대로라면 9,10번째 라인을 사용하면 안된다. ^^ 8라인 처럼 클래스 템플릿일 경우에는 그 실체가 보여야 하므로, Tree 클래스 템플릿 위에 Node 클래스 템플릿이 존재 해야만 한다. 하지만 그냥 class 일 때는 이 조건이 붙지 않고 그냥 쓸 쓸 수 있다.

8.4.1 함수 템플릿에서의 프렌드
함수 템플릿이 프렌드로 선언하려면 꺽!쇠! 를 붙여 주면 된다.  다음 코드를 봐보자.

만약 꺽쇠를 붙여 주지 않는다면, 두가지 상황에 대해서 생각해 볼 수 있다.

  1. 한정자(::)가 없다면, 함수 템플릿은 절대 인스턴스화 될 수 없고, 전역 함수 중에 맞아 떨어지는것으로 friend 선언이 된다. 이 때, 맞아 떨어지는게 없다면, 그 함수에 대한 첫번째 선언이 되거나 정의가 될 수 있다.
  2. 이름이 한정 되었다면, 그 한정된 장소의 함수나 함수 템플릿일 수 있으며, 두개가 공존했을 때, 일반 함수의 선택 우선순위가 높으므로 일반 함수가 선택 된다.


클래스 템플릿에서 프린드 함수를 선언하고 정의할 때 주의해야 할 것이 있는데, 다음의 코드를 인스턴스를 하면 그 이유를 쉽게 알 수 있을 것이다.

14번째 라인에서 에러가 나는데, 그 이유는 13번째에 classtemplate<int>가 인스턴스화 될 때 void ::f(); 가 인스턴스가 된다! 그리고 14번째 classtemplate<char> 가 인스턴스화 될때 다시 void ::f()가 인스턴스화 되기 때문에 ODR을 어기게 되는 것이다. 물론 이것을 피하고 싶다면 void ::f()를 함수 템플릿으로 선언하고 클래스 템플릿의 파라미터를 이용하면 된다.


8.4.2 프렌드 템플릿
프렌드 템플릿이란, 클래스나 클래스 템플릿 안에서 프렌드 선언과 함께 선언한 템플릿 코드를 뜻한다. 다음 코드를 보자.

여기서 10 ~ 11 라인이 바로 프렌드 템플릿이다. 모든 f(T) 에 대해서 classtemplate 이 참조 할 수 있는 장점이 있다. 물론 필요할 경우에만 써야겠지만...

여담 - friend 와 캡슐화에 대한 생각
friend 선언은 캡슐화를 무너뜨리기 때문이라고 사용하면 안된다라고 생각하여 안쓰도록 코드를 짯었다. 하지만, 요즘은 생각이 바뀌었다. 코드를 짜다 보니까, 인터페이스를 만드는게 오히려 더 위험할 수도 있다는 것이다.

각 인터페이스를 만들지 않고도, 단 하나, 또는 내가 지정한 클래스에서만  접근을 허용 하게 만들 수 있기 때문에, 더 캡슐화를 해 줄 수 있다는 뜻이다. 쉽게 생각해서 get/set을 만들면, 모든 장소에서 get/set 으로 참조가 가능하지만, friend를 쓰면, 인페이스 자체를 구현하지 않고, 내가 정한 지역에서만 접근 할 수 있으므로, 더 캡슐화를 했다고 본다.



  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 라이프코리아트위터 공유하기
  • shared
  • 카카오스토리 공유하기