friend 키워드
friend 키워드는 지정된 해당 함수 혹은 클래스에 대해 자신의 private 나 protected 멤버를 public 권한으로 접근할 수 있도록 합니다.
클래스 전체에 대해 지정할 경우
friend class 클래스명;
전역 함수에 대해 지정할 경우
friend 함수원형;
클래스의 멤버 함수에 대해 지정할 경우
friend 클래스명::함수원형;
friend 키워드는 어디에 사용하는가?
friend 키워드는 객체의 사용을 편하게 만들지만, 객체의 캡슐화를 무너뜨립니다.
friend 를 남발하는건 좋은 습관이 아닙니다.
그러나, 때때로 코드 단위에서 사용 방법을 유도할때 유용하게 쓰이기도 합니다.
#include <iostream>
class SharedNumber
{
private:
int* intPtr;
SharedNumber(int num)
{
this->intPtr = new int;
*this->intPtr = num;
}
public:
int getNumber()
{
return *intPtr;
}
void setNumber(int num)
{
*intPtr = num;
}
friend class SharedNumberFactory;
};
class SharedNumberFactory
{
public:
static SharedNumber MakeSharedNumber(int num)
{
return SharedNumber(num);
}
};
int main(int argc, char** argv)
{
SharedNumber firstShared = SharedNumberFactory::MakeSharedNumber(5);
SharedNumber secondShared = firstShared;
printf("%d %d\n", firstShared.getNumber(), secondShared.getNumber());
secondShared.setNumber(20);
printf("%d %d\n", firstShared.getNumber(), secondShared.getNumber());
return 0;
}
5 5
20 20
위의 코드는 사용 예제입니다.
SharedNumber 는 복사된 모든 인스턴스들이 같은 숫자를 가르키도록 디자인 되었습니다.
- 생성자를 숨기고 SharedNumberFactory 에만 friend 로 접근을 허용합니다.
- SharedNumberFactory 에서만 SharedNumber 의 최초 생성을 할 수 있습니다.
SharedNumber 는 int 형 포인터 하나를 가지고 있으며 최초 생성시 메모리를 할당합니다.
자연스럽게 복사된 다른 SharedNumber 는 같은 포인터를 가집니다.
즉, SharedNumberFactory 를 통해서만 SharedNumber 를 생성할 수 있도록 코드 상에서 제한을 한 것입니다.
- 이 규칙을 지키지 않으면 컴파일 에러가 나기 때문에 런타임에 에러를 발견하는 것 보다 훨씬 안전합니다.
static SharedNumber MakeSharedNumber(int num)
별도의 상속 절차가 없는 경우에는 SharedNumber 내 상기 구현을 통해 Factory Class 대신 사용하기도 합니다.
friend 키워드를 사용할때의 선언 배치
class 에 대해 지정을 할 때에는 별다른 문제가 없지만, 전역 함수나 멤버 함수의 경우 반드시 friend 의 대상이 되는 선언이 앞서서 나와야 합니다. 만약 위의 예제를 멤버 함수에 대해 지정할 경우 아래와 같이 선언해야 합니다.
// SharedNumberFactory의 메소드 선언에 필요
class SharedNumber;
class SharedNumberFactory
{
public:
// SharedNumber의 friend 선언에 필요
static SharedNumber MakeSharedNumber(int num);
};
class SharedNumber
{
private:
int* intPtr;
SharedNumber(int num)
{
this->intPtr = new int;
*this->intPtr = num;
}
public:
int getNumber()
{
return *intPtr;
}
void setNumber(int num)
{
*intPtr = num;
}
friend class SharedNumber SharedNumberFactory::MakeSharedNumber(int num);
};
SharedNumber SharedNumberFactory :: MakeSharedNumber(int num)
{
return SharedNumber(num);
}