Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ friend 키워드 완벽 정리: 언제, 어떻게 사용해야 할까?

클래스의 friend 함수는 해당 클래스의 범위(scope) 외부에서 정의되지만, 클래스의 모든 private 및 protected 멤버에 접근할 수 있는 특별한 권한을 가집니다. friend 함수의 원형(prototype)이 클래스 정의 내부에 선언되긴 하지만, friend는 엄밀히 말해 멤버 함수가 아닙니다.

friend로 지정할 수 있는 대상

friend는 일반 함수, 함수 템플릿, 멤버 함수가 될 수 있으며, 클래스나 클래스 템플릿도 friend로 지정할 수 있습니다. 클래스를 friend로 선언하면 그 클래스 전체와 모든 멤버가 friend 권한을 갖게 됩니다.

friend 함수 선언 방법

함수를 클래스의 friend로 선언하려면 클래스 정의 안에서 함수 원형 앞에 friend 키워드를 붙이면 됩니다.

class Box {
    double width;
public:
    double length;
    friend void printWidth(Box box);
    void setWidth(double wid);
};

한 클래스의 모든 멤버 함수를 다른 클래스의 friend로 만들 수도 있습니다. 예를 들어 ClassTwo의 모든 멤버 함수를 ClassOne의 friend로 선언하려면, ClassOne의 정의 안에 다음 한 줄을 추가하면 됩니다.

friend class ClassTwo;

예제 코드

#include <iostream>
using namespace std;

class Box {
    double width;
public:
    friend void printWidth(Box box);
    void setWidth(double wid);
};

// 멤버 함수 정의
void Box::setWidth(double wid) {
    width = wid;
}

// 참고: printWidth()는 어떤 클래스의 멤버 함수도 아닙니다.
void printWidth(Box box) {
    /* printWidth()는 Box의 friend이므로
       이 클래스의 모든 멤버에 직접 접근할 수 있습니다 */
    cout << "Width of box : " << box.width << endl;
}

// 프로그램의 main 함수
int main() {
    Box box;

    // 멤버 함수를 통해 박스의 너비 설정
    box.setWidth(10.0);

    // friend 함수를 사용해 너비 출력
    printWidth(box);

    return 0;
}

실행 결과

Width of box: 10

printWidth() 함수는 Box 클래스의 멤버가 아니었음에도 불구하고, private 멤버 변수인 width에 직접 접근해 값을 출력할 수 있었습니다. 이처럼 friend는 캡슐화의 경계를 선택적으로 완화해 주는 강력한 도구입니다.

friend를 활용하면 좋은 상황

friend를 남용하면 캡슐화가 깨지고 코드 간 결합도가 높아질 수 있으므로 신중하게 사용해야 하지만, 다음과 같은 경우에는 특히 유용합니다.

  • 연산자 오버로딩: operator<<operator>>처럼 왼쪽 피연산자가 ostream/istream 객체인 연산자를 구현할 때 friend 함수가 사실상 필수적입니다.
  • 밀접하게 협력하는 두 클래스: 서로의 내부 데이터를 자주 공유해야 하는 클래스들이 있을 때, getter/setter를 남발하는 것보다 friend 선언이 더 깔끔할 수 있습니다.
  • 팩토리 함수나 헬퍼 함수: 객체 생성 과정에서 내부 멤버에 접근해야 하는 유틸리티 함수에 friend 권한을 부여할 수 있습니다.

정리

friend는 클래스 외부의 함수나 다른 클래스에게 private/protected 멤버 접근 권한을 부여하는 C++의 접근 제어 메커니즘입니다. 멤버 함수로 만들기 어려운 연산자 오버로딩이나 긴밀한 클래스 간 협력이 필요한 상황에서 활용하되, 캡슐화 훼손을 최소화할 수 있도록 최소한의 범위로만 지정하는 것이 바람직합니다.