icon

안동민 개발노트

9장 : 객체 지향 프로그래밍 기초

프렌드 함수와 프렌드 클래스


이전 절 ‘연산자 오버로딩 기초’에서 friend 키워드를 간단히 사용했습니다.

이번 절에서는 friend 문법 자체를 독립적으로 다룹니다. friend는 캡슐화를 일부 우회하는 강력한 도구이므로, 정확한 용도와 한계를 알고 사용하는 것이 중요합니다.


friend란 무엇인가?

friend클래스 외부의 특정 함수 또는 클래스에게 해당 클래스의 private/protected 멤버 접근 권한을 부여하는 키워드입니다.

즉, “이 함수(또는 이 클래스)만 특별히 내부 구현에 접근하도록 허용”하는 선언입니다.


프렌드 함수 (friend function)

프렌드 함수는 클래스의 멤버 함수는 아니지만, 멤버처럼 내부 데이터에 접근할 수 있습니다.

프렌드 함수 기본 예시
#include <iostream>

class Box {
private:
    int width;
    int height;

public:
    Box(int w, int h) : width(w), height(h) {}

    // area 함수에 private 접근 권한 부여
    friend int area(const Box& b);
};

int area(const Box& b) {
    return b.width * b.height; // private 멤버 접근 가능
}

int main() {
    Box b(3, 4);
    std::cout << area(b) << "\n"; // 12
}

프렌드 함수는 객체를 호출 주체(this)로 갖지 않으므로, 좌측 피연산자가 클래스 객체가 아닌 경우(예: std::cout << obj)에 특히 유용합니다.


프렌드 클래스 (friend class)

특정 클래스 전체에 접근 권한을 주고 싶을 때는 friend class를 사용합니다.

프렌드 클래스 예시
#include <iostream>
#include <string>

class SecretVault {
private:
    std::string code{"A1B2C3"};

    friend class VaultInspector; // VaultInspector는 private 접근 가능
};

class VaultInspector {
public:
    void printCode(const SecretVault& vault) const {
        std::cout << "Vault code: " << vault.code << "\n";
    }
};

int main() {
    SecretVault vault;
    VaultInspector inspector;
    inspector.printCode(vault);
}

프렌드 클래스는 권한 범위가 넓으므로, 필요한 최소 범위로 제한하는 것이 좋습니다.


operator<<와 프렌드의 관계

operator<<는 보통 다음 이유로 프렌드 함수로 선언됩니다.

  • 좌측 피연산자가 std::ostream이므로 멤버 함수로 만들기 부적합
  • 객체 내부 상태를 출력하려면 private 접근이 필요한 경우가 많음
operator<< 프렌드 패턴
#include <iostream>

class Point {
private:
    int x, y;

public:
    Point(int _x, int _y) : x(_x), y(_y) {}
    friend std::ostream& operator<<(std::ostream& os, const Point& p);
};

std::ostream& operator<<(std::ostream& os, const Point& p) {
    os << "(" << p.x << ", " << p.y << ")";
    return os;
}

이 패턴은 ‘연산자 오버로딩 기초’와 함께 이해하면 더 명확합니다.

다형성 계층(기반/파생 클래스)에서 출력 연산자를 설계할 때도 같은 원칙이 적용됩니다. operator<<의 피연산자를 값(Base)으로 받으면 객체 슬라이싱이 발생할 수 있으므로, 보통 const Base&를 사용해 다형성을 유지합니다. 이 개념은 10장의 ‘다형성과 가상 함수’와 함께 보면 설계 의도가 더 분명해집니다.


중요한 특성: 상속/전이되지 않음

friend 관계는 직관과 달리 전이되지 않습니다.

  • A가 B의 friend라고 해서, B의 friend인 C가 A의 friend가 되지는 않습니다.
  • 파생 클래스가 생겨도 자동으로 friend 권한이 이어지지 않습니다.
  • friend 선언은 양방향이 아닙니다.

즉, 정확히 선언한 대상에만 권한이 부여됩니다.


friend 사용 시 주의사항

캡슐화 약화

무분별한 friend는 클래스 내부 구현을 외부에 과도하게 노출합니다.

결합도 증가

friend 대상과의 의존성이 강해져 리팩터링이 어려워질 수 있습니다.

최소 권한 원칙

가능하면 friend class보다 friend function처럼 좁은 범위를 우선 고려합니다.


대체 설계는 없는가?

항상 friend가 정답은 아닙니다.

  • 읽기 전용 정보라면 const 게터 제공
  • 조작이 필요하면 공개 인터페이스(멤버 함수)로 의도 명시
  • 출력 전용이라면 필요한 정보만 직렬화 함수로 제공

friend는 “공개 API로 표현하기 어려운 제한된 경우”에 선택하는 것이 보통 더 안전합니다.


friend 사용 원칙 요약

  • friend는 특정 외부 함수/클래스에 내부 접근 권한을 부여한다.
  • 연산자 오버로딩(operator<<)에서 매우 자주 사용된다.
  • 상속/전이/양방향이 아니므로 권한 범위를 정확히 제어할 수 있다.
  • 강력하지만 캡슐화를 약화시키므로 최소 범위로 제한해 사용해야 한다.

목차