프렌드
프렌드(friend)
C++에서 객체의 private 멤버에는 해당 객체의 public 멤버 함수를 통해서만 접근할 수 있다고 했습니다.
하지만 경우에 따라서는 해당 객체의 멤버 함수가 아닌 함수도 private 멤버에 접근해야만 할 경우가 발생합니다.
이럴 때마다 매번 private 멤버에 접근하기 위한 새로운 public 멤버 함수를 작성하는 것은 매우 비효율적입니다.
따라서 C++에서는 이러한 경우를 위해 프렌드(friend)라는 새로운 접근 제어 키워드를 제공합니다.
프렌드는 지정한 대상에 한해 해당 객체의 모든 멤버에 접근할 수 있는 권한을 부여해 줍니다.
이러한 friend 키워드는 전역 함수, 클래스, 멤버 함수의 세 가지 형태로 사용할 수 있습니다.
프렌드 함수 선언
C++에서 프렌드 함수는 friend 키워드를 사용하여 다음과 같이 선언합니다.
원형
friend 클래스이름 함수이름(매개변수목록);
이렇게 선언된 프렌드 함수는 클래스 선언부에 그 원형이 포함되지만, 클래스의 멤버 함수는 아닙니다.
이러한 프렌드 함수는 해당 클래스의 멤버 함수는 아니지만, 멤버 함수와 같은 접근 권한을 가지게 됩니다.
프렌드의 필요성
C++에서 클래스에 대해 이항 연산자를 오버로딩할 때 프렌드의 필요성이 자주 발생합니다.
그 이유는 바로 멤버 함수의 호출 형태에 있습니다.
멤버 함수는 왼쪽 피연산자인 객체가 호출하는 형태이므로, 이항 연산자의 매개변수 순서라든가 타입에 민감해집니다.
하지만 멤버 함수가 아닌 함수를 사용하면 해당 객체의 private 멤버에 접근할 수 없게 됩니다.
따라서 이때 사용하는 것이 바로 프렌드(friend)입니다.
다음 예제는 사각형을 나타내는 Rect 클래스를 정의하면서, 크기를 조절하기 위해 곱셈 연산자(*)를 오버로딩하는 예제입니다.
실행 결과
이 사각형의 높이는 20이고, 너비는 40입니다.
위 예제의 operator*() 함수에서 주석 처리된 구문처럼 피연산자의 순서를 바꾸어 실행하면 오류가 발생할 것입니다.
그 이유는 멤버 함수란 왼쪽 피연산자인 객체가 호출하는 형태가 되어야 하기 때문입니다.
따라서 두 구문이 모두 정상적으로 동작하기 위해서는 지금의 operator*() 함수뿐만 아니라 매개변수의 순서가 다른 또 하나의 operator*() 함수를 객체가 호출하지 않는 전역 함수로 작성해야 합니다.
그 전역 함수가 private 멤버인 height_와 width_에 접근하기 위해서는 friend 키워드를 추가해야 합니다.
예제
class Rect
{
private:
double height_;
double width_;
public:
Rect(double height, double width); // 생성자
void DisplaySize();
Rect operator*(double mul) const;
friend Rect operator*(double mul, const Rect& origin); // 프렌드 함수
};
...
Rect Rect::operator*(double mul) const { return Rect(height_ * mul, width_ * mul); }
Rect operator*(double mul, const Rect& origin) { return origin * mul; }
실행 결과
이 사각형의 높이는 20이고, 너비는 40입니다.
이 사각형의 높이는 30이고, 너비는 60입니다.
상수 멤버 함수란 자신이 호출하는 객체를 수정하지 않는 읽기 전용 함수를 의미합니다.