83

유형이 있고 기본 생성자를 비공개로 설정하려고한다고 가정 해 보겠습니다. 나는 다음을 쓴다 :개인 생성자가 개인 생성자가 아닌 경우는 언제입니까?

class C { 
    C() = default; 
}; 

int main() { 
    C c;   // error: C::C() is private within this context (g++) 
        // error: calling a private constructor of class 'C' (clang++) 
        // error C2248: 'C::C' cannot access private member declared in class 'C' (MSVC) 
    auto c2 = C(); // error: as above 
} 

위대한. 이것은 매우 놀라운 예상치 못한, 명시 적으로 바람직하지 않은 행위 나 파업

class C { 
    C() = default; 
}; 

int main() { 
    C c{};   // OK on all compilers 
    auto c2 = C{}; // OK on all compilers 
}  

: 내가 생각했던대로

하지만, 생성자가 밝혀 민간 없습니다. 이게 왜 괜찮은거야?

+21

이 아닌가'C의 C {}; '초기화를 집계하여 생성자가 호출되지 않았습니까? – NathanOliver

+5

@ NathanOliver가 말한 바. 사용자 제공 생성자가 없으므로 'C'는 집계입니다. –

+5

@KerrekSB 동시에 사용자에게 명시 적으로 ctor를 선언해도 사용자가 제공 한 ctor가 아니라는 것은 나에게 상당히 놀라운 일이었습니다. – Angew

답변

56

트릭 인 C++ 8.4.2 14/5 [dcl.fct.def.default]

... 함수이다 사용자 제공은 사용자가 선언 된 경우 명시 적으로 기본값이 지정되지 않았거나 이 첫 번째 선언에서 삭제되었습니다. ...

C의 기본 생성자가 실제로 있다는 것을 의미

하지 사용자 제공, 명시 적으로 최초의 선언을 이행하지 않았기 때문에. 이와 같이, C에는 사용자가 제공 한 생성자가 없으며, 따라서 당 집합체이다 8.5.1/1 dcl.init.aggr]

집합체은 배열 또는 클래스 (9 절)와 사용자 제공 생성자 (12.1), 비공개 데이터 멤버 (11 절), 기본 클래스 없음 (10 절) 및 가상 함수 없음 (10.3)이 없습니다.

+12

실제로 작은 표준 결함 :이 컨텍스트에서 기본 ctor가 비공개 였음을 실제로 무시합니다. – Yakk

+2

@Yakk 나는 판단 할 자격이 없다고 느낍니다. 사용자가 제공하지 않는 ctor에 대한 표현은 매우 신중하게 보입니다. – Angew

+1

@Yakk : 음, 그렇습니다. 클래스에 데이터 멤버가있는 경우 해당 멤버를 비공개로 설정할 수 있습니다. 데이터 회원이 없으면이 상황이 심각한 영향을 미칠 수있는 상황이 거의 없습니다. –

49

기본 생성자를 호출하지 않고 집계 유형에 대해 집계 초기화를 사용하고 있습니다. 집계 유형이 선언 제 어디가 디폴트 그래서 긴 같은 부도 생성자를 가질 수있다 :

[dcl.init.aggr]/1에서 :

이 집합체

으로 배열 또는 클래스 (조 [급]) 인
  • 에는 사용자가 제공 생성자 ([class.ctor),
  • 없이 개인 또는 보호 된 비 정적 데이터 멤버 (조 [클래스 (([namespace.udecl])베이스 클래스로부터 상속 포함). 액세스]),
  • 가상 함수 ([class.virtual])가없고
  • 가상, 개인 또는 보호 된 기본 클래스 ([class.mi])가 없습니다.

[dcl.fct.def.default]/5

명시 적으로-궐석 기능과 암시 적으로 선언 함수에서 일괄 채무 불이행 함수라고하며, 구현 그들 ([class.ctor] [클래스에 대한 암시 적 정의를 제공하여야한다. dtor], [class.copy]), 삭제 된 것으로 정의 할 수 있습니다. 함수는 사용자가 선언하고 명시 적으로 기본값을 지정하거나 삭제하지 않은 경우 사용자가 제공합니다. 사용자 제공 명시 적 기본값 함수 (즉, 첫 번째 선언 이후 명시 적으로 기본값 지정)는 명시 적으로 기본값으로 설정되는 시점에서 정의됩니다. 그러한 함수가 암시 적으로 삭제됨으로 정의되면 프로그램이 잘못 작성됩니다. [참고 : 첫 번째 선언 이후에 기본값으로 함수를 선언하면 효율적인 실행 및 간결한 정의를 제공 할 수 있으며 안정적인 이진 인터페이스에서 진화하는 코드 기반을 사용할 수 있습니다. - 끝 참고 따라서

, 총에 대한 우리의 요구 사항은 없습니다 :

  • 에는 비공개 회원
  • 에는 가상 함수
  • 없는 가상 또는 비공개 기본 클래스
  • 사용자가 제공 한 생성자가 상속되거나 그렇지 않으면 생성자 만 허용됩니다.
    • 이 암시 적으로 선언되거나
    • 이 명시 적으로 선언되고 동시에 기본값으로 정의됩니다.

C는 이러한 요구 사항을 모두 충족합니다.

당연히, 당신이, 또는 선언 한 후 기본값으로 생성자를 정의하여 단순히 빈 기본 생성자를 제공하여이 거짓 기본 구조 동작을 제거 할 수 있습니다

class C { 
    C(){} 
}; 
// --or-- 
class C { 
    C(); 
}; 
inline C::C() = default; 
+2

저는이 답변을 Angew의 답변보다 다소 좋아하지만 처음에는 요약문에서 최대 두 문장의 혜택을 볼 것이라고 생각합니다. – PJTraill

관련 문제