동반자 (C++ 전용)
클래스 X
의 동반자는 X
의 멤버가 아닌 함수 또는 클래스이지만 X
의 멤버와 동일한 X
에 대한 액세스 권한이 부여됩니다. 클래스 멤버 목록에서 friend
지정자로 선언된 함수를 해당 클래스의 프렌드 함수 라고 합니다. 다른 클래스의 멤버 목록에서 friend
지정자로 선언된 클래스를 해당 클래스의 동반자 클래스 라고 합니다.
Y
의 멤버가 다른 클래스의 동반자로 선언되기 전에 Y
클래스를 정의해야 합니다.
다음 예에서 동반자 함수 print
는 Y
클래스의 멤버이며 X
클래스의 개인용 데이터 멤버 a
및 b
에 액세스합니다.
#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
의 개인용 데이터 멤버 a
및 b
에 액세스하고 위 예제의 동반자 함수 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 만의 시작.
확장된 동반자 선언
참고: 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를 사용할 수 없습니다. 다음 예제에서 템플리트 매개변수 T
를 F
클래스의 동반자로 선언할 수 있으며 동반자 선언에서 기본 유형 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 D
이 Base
클래스의 동반자로 선언되었음을 보여줍니다.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 의 끝.