동반자 (C++ 전용)

클래스 X 의 동반자는 X의 멤버가 아닌 함수 또는 클래스이지만 X의 멤버와 동일한 X 에 대한 액세스 권한이 부여됩니다. 클래스 멤버 목록에서 friend 지정자로 선언된 함수를 해당 클래스의 프렌드 함수 라고 합니다. 다른 클래스의 멤버 목록에서 friend 지정자로 선언된 클래스를 해당 클래스의 동반자 클래스 라고 합니다.

Y 의 멤버가 다른 클래스의 동반자로 선언되기 전에 Y 클래스를 정의해야 합니다.

다음 예에서 동반자 함수 printY 클래스의 멤버이며 X클래스의 개인용 데이터 멤버 ab 에 액세스합니다.

#include <iostream>
using namespace std;

class X;

class Y {
public:
  void print(X& x);
};

class X {
  int a, b;
  friend void Y::print(X& x);
public:
  X() : a(1), b(2) { }
};

void Y::print(X& x) {
  cout << "a is " << x.a << endl;
  cout << "b is " << x.b << endl;
}

int main() {
  X xobj;
  Y yobj;
  yobj.print(xobj);
}
다음은 위 예제의 출력입니다.
a is 1
b is 2

전체 클래스를 동반자로 선언할 수 있습니다. F 클래스가 A클래스의 동반자라고 가정하십시오. 이는 F 클래스의 모든 멤버 함수 및 정적 데이터 멤버 정의에 A클래스에 대한 액세스 권한이 있음을 의미합니다.

다음 예제에서 동반자 클래스 F 에는 클래스 X 의 개인용 데이터 멤버 ab 에 액세스하고 위 예제의 동반자 함수 print 와 동일한 태스크를 수행하는 멤버 함수 print 가 있습니다. F 클래스에 선언된 다른 모든 멤버도 X클래스의 모든 멤버에 액세스할 수 있습니다.

#include <iostream>
using namespace std;

class X {
  int a, b;
  friend class F;
public:
  X() : a(1), b(2) { }
};

class F {
public:
  void print(X& x) {
    cout << "a is " << x.a << endl;
    cout << "b is " << x.b << endl;
  }
};

int main() {
  X xobj;
  F fobj;
  fobj.print(xobj);
}
다음은 위 예제의 출력입니다.
a is 1
b is 2
클래스를 동반자로 선언할 때 정제된 유형 지정자를 사용해야 합니다. 다음 예는 이를 보여줍니다.
class F;
class G;
class X {
  friend class F;
  friend G;
};

컴파일러는 G 의 동반자 선언이 정제된 클래스 이름이어야 함을 경고합니다.

동반자 선언에서 클래스를 정의할 수 없습니다. 예를 들어, 컴파일러는 다음을 허용하지 않습니다.
class F;
class X {
  friend class F { };
};
그러나 프렌드 선언에서 함수를 정의할 수 있습니다. 클래스는 비로컬 클래스, 함수이어야 하고, 함수 이름은 규정되지 않아야 하며, 함수에 네임스페이스 범위가 있어야 합니다. 다음 예는 이를 보여줍니다.
class A {
  void g();
};

void z() {
  class B {
//    friend void f() { };
  };
}

class C {
//  friend void A::g() { }
  friend void h() { }
};
컴파일러는 f() 또는 g()의 함수 정의를 허용하지 않습니다. 컴파일러는 h()의 정의를 허용합니다.

스토리지 클래스 지정자를 사용하여 동반자를 선언할 수 없습니다.

C++11 C++11 만의 시작.

확장된 동반자 선언

참고: IBM® 은 C++11의 선택된 기능 ( C++0x 로 알려짐) 을 승인 전에 지원합니다. IBM 은 새 표준의 기능을 계속 개발하고 구현합니다. 언어 레벨의 구현은 이 표준에 대한 IBM의 해석을 기반으로 합니다. 새 C++ 표준 라이브러리의 지원을 포함하여 IBM의 모든 C++11 기능 구현이 완료될 때까지 구현은 릴리스에 따라 변경될 수 있습니다. IBM 은 IBM의 새 C++11 기능 구현의 이전 릴리스와의 소스, 2진또는 목록 및 기타 컴파일러 인터페이스에서 호환성을 유지하려고 시도하지 않으므로 안정적인 프로그래밍 인터페이스로 의존해서는 안됩니다.
참고: 확장된 동반자 선언의 구문 양식은 IBM 이전 동반자 선언 구문과 겹칩니다. 이 절에서는 C++11 표준과 이전 ISO C++ 표준 간의 차이점에 초점을 맞춥니다.
이 기능을 사용하면 동반자 선언의 컨텍스트에서 클래스 키가 더 이상 필요하지 않습니다. 이 새 구문은 C++98 동반자 클래스 선언 구문과 다릅니다. 여기서 class-key는 정교한 유형 지정자의 일부로 필요합니다. 다음 예를 참조하십시오.
class F;
class G;
class X1 {
    //C++98 friend declarations remain valid in C++11.
    friend class F;
    //Error in C++98 for missing the class-key.
    friend G;
};
class X2 {
    //Error in C++98 for missing the class-key.
    //Error in C++11 for lookup failure (no previous class D declaration).
    friend D;
    friend class D;
};
함수 및 클래스 외에도 템플리트 매개변수 및 기본 유형을 동반자로 선언할 수도 있습니다. 이 경우, 프렌드 선언에서 Elaborated-type-specifier를 사용할 수 없습니다. 다음 예제에서 템플리트 매개변수 TF클래스의 동반자로 선언할 수 있으며 동반자 선언에서 기본 유형 char 를 사용할 수 있습니다.
class C;
template <typename T, typename U> class F {
    //C++11 compiles sucessfully.
    //Error in C++98 for missing the class-key.
    friend T;
    //Error in both C++98 and C++11: a template parameter
    //must not be used in an elaborated type specifier.
    friend class U;
};
typedef 이름을 동반자로 선언할 수도 있지만 동반자 선언에서는 여전히 Elaborated-type-specifier를 사용할 수 없습니다. 다음 예제는 typedef name DBase클래스의 동반자로 선언되었음을 보여줍니다.
class Derived;
typedef Derived D;
class C;
typedef C Ct;
class Base{
public:
    Base() : x(55) {}
    //C++11 compiles sucessfully.
    //Error in C++98 for missing the class-key.
    friend D;
    //Error in both C++98 and C++11: a typedef name
    //must not be used in an elaborated type specifier.
    friend class Ct;
private:
    int x;
};
struct Derived : public Base {
    int foo() { return this->x; }
};
int main() {
    Derived d;
    return d.foo();
}
이 기능은 동반자 선언에 대한 새 이름 검색 규칙도 소개합니다. 동반자 클래스 선언이 Elaborated-type-specifier를 사용하지 않는 경우 컴파일러는 동반자 선언을 둘러싸는 가장 안쪽 네임스페이스 외부의 범위에서도 엔티티 이름을 찾습니다. 다음의 예를 고려하십시오:
struct T { };
namespace N {
    struct A {
        friend T;
    };
}
이 예에서 이 기능이 적용되는 경우 동반자 선언 명령문은 새 엔티티 T를 선언하지 않지만 T를 찾습니다. T 가 없으면 컴파일러가 오류를 발행합니다. 다른 예를 생각해 보십시오.
struct T { };
namespace N {
    struct A {
        friend class T; //fine, no error
    };
}
이 예에서 프렌드 선언 명령문은 T 외부 이름 공간 N을 찾지 않으며 ::T도 찾지 않습니다. 대신 이 명령문은 네임스페이스 N에서 새 클래스 T 를 선언합니다.

C++11 C++11 의 끝.