이것은 C ++의 특이한 / 기능입니다. 참조를 유형으로 생각하지 않지만 실제로는 유형 시스템에 "앉아"있습니다. 이것은 어색해 보이지만 (참조가 사용될 때 참조 시맨틱이 자동으로 발생하고 참조가 "비정상적"이라는 점을 감안할 때) 참조가 외부의 별도 속성이 아닌 유형 시스템에서 모델링되는 몇 가지 확실한 이유가 있습니다. 유형.
첫째, 선언 된 이름의 모든 속성이 유형 시스템에 있어야하는 것은 아니라는 점을 고려해 보겠습니다. C 언어에서는 "스토리지 클래스"와 "연결"이 있습니다. 이름은로 도입 될 수 있습니다 extern const int ri
. extern
여기서은 정적 스토리지 클래스 및 링크의 존재를 나타냅니다. 유형은 단지 const int
입니다.
C ++는 표현식이 유형 시스템 외부에있는 속성을 가지고 있다는 개념을 분명히 수용합니다. 이제 언어에는 표현식이 표시 할 수있는 비 유형 속성의 증가하는 수를 구성하려는 시도 인 "값 클래스"개념이 있습니다.
그러나 참조는 유형입니다. 왜?
C ++ 튜토리얼에서는 type을 갖는 것으로 const int &ri
소개 된 ri
것과 같은 선언이 const int
의미론을 참조 한다고 설명했습니다 . 그 참조 의미론은 유형이 아닙니다. 이름과 저장 위치 사이의 비정상적인 관계를 나타내는 일종의 속성 일뿐입니다. 또한 참조가 유형이 아니라는 사실은 유형 생성 구문이 허용하더라도 참조를 기반으로 유형을 생성 할 수없는 이유를 합리화하는 데 사용되었습니다. 예를 들어, 참조에 대한 배열 또는 포인터는 불가능합니다 : const int &ari[5]
및 const int &*pri
.
그러나 실제로 참조 는 유형이므로 decltype(ri)
규정되지 않은 일부 참조 유형 노드를 검색합니다. 를 사용하여 기본 유형에 도달하려면 유형 트리에서이 노드를지나 내려 가야합니다 remove_reference
.
를 사용 ri
하면 참조가 투명하게 확인되므로 ri
"모양 및 느낌 i
"이되며 "별칭"이라고 할 수 있습니다. 그러나 유형 시스템에서는 ri
실제로 " reference to const int
"인 유형이 있습니다.
왜 참조 유형입니까?
참조가 유형 이 아니라면 이러한 함수는 동일한 유형을 갖는 것으로 간주됩니다.
void foo(int);
void foo(int &);
그것은 거의 자명 한 이유 때문일 수 없습니다. 유형이 같으면 선언이 어느 정의 에나 적합하므로(int)
함수가 참조를받는 것으로 의심되어야합니다.
마찬가지로 참조가 유형이 아닌 경우 다음 두 클래스 선언은 동일합니다.
class foo {
int m;
};
class foo {
int &m;
};
한 번역 단위가 하나의 선언을 사용하고 동일한 프로그램의 다른 번역 단위가 다른 선언을 사용하는 것이 옳습니다.
사실 참조는 구현의 차이를 의미하며 C ++의 유형은 엔티티의 구현과 관련이 있기 때문에이를 유형과 분리하는 것은 불가능합니다. 말하자면 비트 단위의 "레이아웃"입니다. 두 함수의 유형이 동일한 경우 동일한 이진 호출 규칙으로 호출 할 수 있습니다. ABI는 동일합니다. 두 구조체 또는 클래스의 유형이 동일한 경우 해당 레이아웃은 모든 멤버에 대한 액세스 의미뿐만 아니라 동일합니다. 참조의 존재는 유형의 이러한 측면을 변경하므로이를 유형 시스템에 통합하는 것은 간단한 디자인 결정입니다. (그러나 여기에서 반론에 유의하십시오. 구조체 / 클래스 멤버는 일 수 있으며 static
표현도 변경되지만 유형이 아닙니다!)
따라서 참조는 유형 시스템에서 "두 번째 클래스 시민"으로 존재합니다 (ISO C의 함수 및 배열과 다르지 않음). 참조에 대한 포인터 또는 배열의 선언과 같이 참조로 "할 수없는"특정 작업이 있습니다. 그러나 그것이 그들이 유형이 아니라는 것을 의미하지는 않습니다. 말이되는 방식으로 유형이 아닙니다.
이러한 모든 2 등급 제한이 필수적인 것은 아닙니다. 참조 구조가 있다는 점을 감안할 때 참조 배열이있을 수 있습니다! 예
int x = 0, y = 0;
int &ar[2] = { x, y };
이것은 C ++로 구현되지 않은 것뿐입니다. 참조에 대한 포인터는 전혀 의미가 없습니다. 참조에서 들어온 포인터는 참조 된 개체로 이동하기 때문입니다. 참조 배열이없는 이유는 C ++ 사람들이 배열을 C에서 상속 된 일종의 저수준 기능으로 생각하고 복구 할 수없는 여러 가지 방법으로 깨져서 배열을 터치하고 싶지 않기 때문입니다. 새로운 것을위한 기초. 그러나 참조 배열의 존재는 참조가 유형이되어야하는 방법에 대한 명확한 예가 될 것입니다.
비const
적격 유형 : ISO C90에도 있습니다!
일부 답변은 참조가 const
한정자를 사용 하지 않는다는 사실을 암시합니다 . 선언 const int &ri = i
이 정규화 된 참조 를 만들 려고 시도 하지 않기 때문에 오히려 빨간색 청어입니다 const
. 이것은 const 정규화 된 유형에 대한 참조입니다 (그 자체가 아닙니다 const
). const in *ri
무언가에 대한 포인터를 선언하는 것처럼 const
포인터 자체는const
.
즉, 참고 문헌이 const
한정자를 .
그러나 이것은 그렇게 기괴하지 않습니다. ISO C 90 언어에서도 모든 유형이const
. 즉, 배열이 될 수 없습니다.
첫째, const 배열을 선언하기위한 구문이 존재하지 않습니다. int a const [42]
.
그러나 위 선언이하려는 것은 중간을 통해 표현할 수 있습니다 typedef
.
typedef int array_t[42];
const array_t a;
그러나 이것은 그것이하는 것처럼 보이는 것을하지 않습니다. 이 선언에서 자격 a
이 const
부여 되는 것은 요소가 아니라 요소입니다! 즉, a[0]
는 const int
이지만 a
"int의 배열"입니다. 따라서 진단이 필요하지 않습니다.
int *p = a;
이것은 다음을 수행합니다.
a[0] = 1;
다시 말하지만, 이것은 참조가 배열과 같은 유형 시스템에서 어떤 의미에서 "두 번째 클래스"라는 생각을 강조합니다.
배열에도 참조와 같은 "보이지 않는 변환 동작"이 있기 때문에 비유가 훨씬 더 깊이 유지되는 방법에 유의하십시오. 프로그래머가 명시 적 연산자를 사용할 필요가 없으면 식별자 는식이 사용 된 것처럼 a
자동으로 int *
포인터 로 바뀝니다 &a[0]
. 이것은 참조를 ri
기본 표현식으로 사용할 때 참조가 마술처럼 객체를 나타내는 것과 유사 합니다.i
가 바인딩 된 를 . "포인터 붕괴에 대한 배열"과 같은 또 다른 "감쇠"입니다.
그리고 "포인터에 대한 배열"이 "배열은 C와 C ++의 포인터 일뿐"이라고 잘못 생각하는 것으로 혼동해서는 안되는 것처럼 참조가 자신의 유형이없는 별칭 일 뿐이라고 생각해서는 안됩니다.
경우 decltype(ri)
그 지시 대상 객체에 대한 참조의 일반적인 변환을 억제,이 다르지 아니다 sizeof a
어레이 간 포인터 전환을 억제하고, 동작에 어레이 형 자체 의 크기를 계산.
boolalpha(cout)
매우 드물다.std::cout << boolalpha
대신 할 수 있습니다.