비공개 멤버 변수를 C ++ 헤더에 넣는 이유에 대한 대답은 클래스의 크기를 인스턴스가 선언되는 지점에서 알아야 컴파일러가 스택에서 적절하게 움직이는 코드를 생성 할 수 있다는 것입니다.
그러나 클래스 정의에서 개인 함수를 선언 해야하는 이유가 있습니까?
대안은 본질적으로 pimpl 관용구이지만 불필요한 간접 지시는 없을 것입니다.
이 언어 기능은 역사적 오류 이상입니까?
비공개 멤버 변수를 C ++ 헤더에 넣는 이유에 대한 대답은 클래스의 크기를 인스턴스가 선언되는 지점에서 알아야 컴파일러가 스택에서 적절하게 움직이는 코드를 생성 할 수 있다는 것입니다.
그러나 클래스 정의에서 개인 함수를 선언 해야하는 이유가 있습니까?
대안은 본질적으로 pimpl 관용구이지만 불필요한 간접 지시는 없을 것입니다.
이 언어 기능은 역사적 오류 이상입니까?
답변:
개인 멤버 함수는 virtual이며, vtable을 사용하는 C ++의 일반적인 구현에서는 클래스의 모든 클라이언트가 특정 순서와 가상 함수 수를 알아야합니다. 하나 이상의 가상 멤버 함수가 인 경우에도 적용됩니다 private.
컴파일러 구현 선택은 언어 사양에 영향을 미치지 않기 때문에 이것이 "마차 앞에 카트를 넣는"것처럼 보일 수 있습니다. 그러나 실제로 C ++ 언어 자체는 vtables를 사용 하는 실제 구현 ( Cfront ) 과 동시에 개발되었습니다 .
정의 외부의 클래스에 메소드를 추가 할 수 있도록 허용 한 경우 모든 파일의 어느 위치에서나 메소드를 추가 할 수 있습니다 .
그러면 모든 클라이언트 코드에 개인 및 보호 된 데이터 멤버에 대한 간단한 액세스 권한이 즉시 부여됩니다.
클래스 정의를 마치면, 파일을 확장하기 위해 일부 파일을 저자가 특별히 축복 한 것으로 표시 할 수 없습니다. 평평한 번역 단위 만 있습니다. 따라서 컴파일러에게 특정 메소드 세트가 공식적이거나 클래스 작성자가 축복 한 것이라고 알리는 유일한 합리적인 방법은 클래스 내부에서 메소드를 선언하는 것입니다.
C ++에서 메모리에 직접 액세스 할 수 있습니다. 이는 일반적으로 클래스와 동일한 메모리 레이아웃으로 섀도우 유형을 만들고, 내 자신의 메서드를 추가하거나 (또는 모든 데이터를 공개로 만드는) 사소한 일임을 의미합니다 reinterpret_cast. 또는 개인 기능 코드를 찾거나 분해 할 수 있습니다. 또는 심볼 테이블에서 함수 주소를 조회하거나 직접 호출하십시오.
이러한 액세스 지정자는 이러한 공격을 막으려 고 시도하지 않습니다. 이것이 불가능하기 때문입니다. 클래스 사용 방법 만 나타냅니다.
수락 된 답변은 가상 개인 기능에 대해 설명 하지만 OP의 요청보다 상당히 제한된 질문의 특정 측면에만 응답합니다. 따라서 우리는 왜 비가 상 개인 함수를 헤더 에 선언해야 합니까?
또 다른 대답은 클래스가 하나의 블록으로 선언되어야한다는 사실을 불러 일으킨 후에는 봉인되어 추가 할 수 없다는 것입니다. 헤더에 개인 메소드를 선언하지 않고 다른 곳에서 정의하려고 시도하여 수행하는 작업입니다. 좋은 지적이야 클래스의 일부 사용자가 다른 사용자가 볼 수없는 방식으로 클래스를 확장 할 수있는 이유는 무엇입니까? 전용 메소드는 그 일부이며 여기에서 제외되지 않습니다. 그러나 왜 그것들이 포함되어 있는지 물어 보면 약간 긴장된 것처럼 보입니다. 왜 클래스 사용자가 그들에 대해 알아야합니까? 그들이 보이지 않는다면, 사용자는 아무것도 추가 할 수 없었으며, 그 결과는 예쁘다.
따라서 기본적으로 개인 메서드를 포함하는 것이 아니라 사용자가 볼 수 있도록 특정 지점을 제공한다는 답변을 제공하고 싶었습니다. 공개 선언이 필요한 비가 상 개인 기능의 기계적인 이유는 Herb Sutter의 GotW # 100에서 Pimpl 관용구 에 대한 이론적 근거의 일부입니다. 나는 우리 모두 그것에 대해 알고 있기 때문에 Pimpl에 대해서는 계속하지 않을 것입니다. 그러나 관련 비트는 다음과 같습니다.
C ++에서 헤더 파일 클래스 정의의 내용이 변경되면 해당 클래스의 모든 사용자는 클래스의 사용자가 액세스 할 수없는 개인 클래스 멤버에 대한 변경 만 있었더라도 다시 컴파일해야합니다. C ++의 빌드 모델은 텍스트 포함을 기반으로하고 C ++에서는 호출자가 개인 구성원의 영향을받을 수있는 클래스에 대해 두 가지 주요 사항을 알고 있다고 가정하기 때문입니다.
- 크기 및 레이아웃 : [멤버 및 가상 기능-자체 설명이 필요하고 성능은 우수하지만 여기에있는 이유는 아님]
- 함수 : 호출 코드는 비 개인 함수로 오버로드되는 액세스 할 수없는 개인 함수를 포함 하여 클래스의 멤버 함수에 대한 호출을 분석 할 수 있어야 합니다. 개인 함수가 더 일치하면 호출 코드가 컴파일되지 않습니다. (C ++은 안전상의 이유로 접근성 검사 전에 과부하 해결을 수행하기 위해 의도적으로 설계 결정을 내 렸습니다. 예를 들어, 함수의 접근성을 개인에서 공공으로 변경한다고해서 법적 호출 코드의 의미가 바뀌지 않아야한다는 느낌이 들었습니다.)
물론 Sutter는위원회 회원으로서 매우 신뢰할 수있는 출처이므로 "고의적 인 설계 결정"을 알고 있습니다. 그리고 나중에 변경된 의미 체계를 피하거나 나중에 실수로 액세스 가능성을 잃지 않도록 개인 메서드를 공개적으로 선언해야한다는 생각이 가장 설득력있는 이유 일 것입니다. 고맙게도, 지금까지 모든 것이 무의미 해 보였습니다!
이렇게하는 데는 두 가지 이유가 있습니다.
먼저, 액세스 지정자는 컴파일러 용 이며 런타임에는 관련이 없음을 인식하십시오. 범위를 벗어난 개인 멤버에 액세스하면 컴파일 오류가 발생합니다.
짧은 한두 줄의 기능을 고려하십시오. 다른 곳에서 코드의 복제를 줄이기 위해 존재합니다. 또한 알고리즘이나 다른 어떤 것이 든 많은 곳이 아닌 한 곳에서 작동하는 방식을 변경할 수 있다는 장점이 있습니다 (예 : 정렬 알고리즘 변경).
헤더에 한두 줄의 빠른 줄이 있거나 함수 프로토 타입과 어딘가에 구현이 있습니까? 헤더에서 찾기가 더 쉬우 며 짧은 기능의 경우 별도의 구현이 훨씬 더 장황합니다.
또 다른 주요 이점이 있습니다.
전용 함수는 인라인 될 수 있으며, 반드시 헤더에 있어야합니다. 이걸 고려하세요:
class A {
private:
inline void myPrivateFunction() {
...
}
public:
inline void somePublicFunction() {
myPrivateFunction();
...
}
};
개인 기능 은 공용 기능과 함께 인라인 될 수 있습니다. inline키워드는 기술적으로 제안 이며 요구 사항이 아니기 때문에 컴파일러의 재량에 따라 수행됩니다 .
inline되므로 키워드를 사용할 이유가 없습니다.
.cpp클래스 정의 외부에 정의 된 멤버 함수에 의해 인라인 된 파일에 비 멤버 함수를 가질 수 있지만 이러한 함수는 개인용이 아닙니다.
헤더 파일에 개인용 메소드가있는 또 다른 이유 : 공용 인라인 메소드가 하나 이상의 개인용 메소드를 호출하는 것보다 많지 않은 경우가 있습니다. 헤더에 개인용 메소드가 있다는 것은 공개 메소드에 대한 호출이 개인용 메소드의 실제 코드에 완전히 인라인 될 수 있으며 인라인이 개인용 메소드에 대한 호출로 중지되지 않음을 의미합니다. 다른 컴파일 단위에서도 (공용 메소드는 일반적 으로 다른 컴파일 단위에서 호출됩니다).
물론 개인 메소드를 포함한 모든 메소드를 모르는 경우 컴파일러가 과부하 해결과 관련된 문제점을 감지 할 수없는 이유도 있습니다.
이러한 기능이 개인 구성원에게 액세스 할 수 있도록 허용합니다. 그렇지 않으면 friend어쨌든 헤더에 있어야합니다.
함수가 클래스의 개인 멤버에 액세스 할 수 있으면 private은 쓸모가 없습니다.