ProgramingTip

C ++ 17에서 보호 된 생성자에 대한 규칙이 변경 되었습니까?

bestdevel 2020. 12. 5. 10:20
반응형

C ++ 17에서 보호 된 생성자에 대한 규칙이 변경 되었습니까?


이 테스트 케이스가 있습니다.

struct A{ protected: A(){} };
struct B: A{};
struct C: A{ C(){} };
struct D: A{ D() = default; };

int main(){
    (void)B{};
    (void)C{};
    (void)D{};
}

gcc와 clang은 모두 C ++ 11 및 C ++ 14 모드로 준비합니다. 둘 다 C ++ 17 모드에서 실패합니다.

$ clang++ -std=c++17 main.cpp 
main.cpp:7:10: error: base class 'A' has protected default constructor
        (void)B{};
                ^
main.cpp:1:22: note: declared protected here
struct A{ protected: A(){} };
                     ^
main.cpp:9:10: error: base class 'A' has protected default constructor
        (void)D{};
                ^
main.cpp:1:22: note: declared protected here
struct A{ protected: A(){} };
                     ^
2 errors generated.

$ clang++ --version
clang version 6.0.0 (http://llvm.org/git/clang.git 96c9689f478d292390b76efcea35d87cbad3f44d) (http://llvm.org/git/llvm.git 360f53a441902d19ce27d070ad028005bc323e61)
Target: x86_64-unknown-linux-gnu
Thread model: posix

(마스터 브랜치 2017-12-05에서 준비 된 clang.)

$ g++ -std=c++17 main.cpp 
main.cpp: In function 'int main()':
main.cpp:7:10: error: 'A::A()' is protected within this context
  (void)B{};
          ^
main.cpp:1:22: note: declared protected here
 struct A{ protected: A(){} };
                      ^
main.cpp:9:10: error: 'A::A()' is protected within this context
  (void)D{};
          ^
main.cpp:1:22: note: declared protected here
 struct A{ protected: A(){} };
                      ^

$ g++ --version
g++ (GCC) 8.0.0 20171201 (experimental)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

이 동작 변경은 C ++ 17의 일부입니까 아니면 두 컴파일러 모두의 버그입니까?


존재 의 정의는 C ++ 17 이후 변경되었습니다.

C ++ 17 이전

기본 클래스 없음

C ++ 17 이후

virtual, private, or protected (since C++17)기본 클래스 없음

즉, for Band D는 C ++ 17 이전에 존재 유형이 for B{}and D{}, 초기화가 수행되고 기본 기본 생성자가 호출 됩니다. protected기본 클래스의 생성자는 클래스의 생성자에 의해 호출 될 수 있기 때문에 괜찮습니다 .

C ++ 17 일 이후 BD(그들은 단지 때문에 집계 유형이 될 public기본 클래스 및 메모를 클래스의 것을 D위해 다음, 명시 적으로 부도 기본 생성자 (11) C ++ 이후 집계 유형에 허용되는) B{}D{}, 집계 초기화가 될 것입니다 수행,

direct public base, (since C++17)배열 요소 또는 비 정적 클래스 멤버는 클래스 정의의 배열 첨자 / 모양 순서대로 초기화 목록의 해당 절에서 복사 초기화됩니다.

이니셜 라이저 절의 수가 멤버 수보다 적 and bases (since C++17)거나 이니셜 라이저 목록이 완전히 비어있는 경우, 나머지 멤버 and bases (since C++17)by their default initializers, if provided in the class definition, and otherwise (since C++14)일반 목록 초기화 규칙에 따라 빈 목록으로 초기화됩니다 (비 클래스 유형에 대해 값 초기화를 수행하고 기본 생성자가있는 비 집계 클래스 및 집계에 대한 집계 초기화). 참조 유형의 멤버가 이러한 나머지 멤버 중 하나 인 경우 프로그램은 잘못된 것입니다.

즉, 기본 클래스의 하위 객체 값으로 초기화 직접 생성자 것이다 수단 BD우회이고; 그러나의 기본 생성자는 A이면 protected코드가 실패합니다. ( A사용자가 제공 한 생성자가 있으므로 집계 유형이 아닙니다.)

BTW : C(사용자 제공 생성자 사용) C ++ 17 전후의 집계 유형이 아니므로 두 경우 모두 괜찮습니다.


C ++ 17에서는 집계에 대한 규칙이 변경되었습니다.

예를 들어 이제 C ++ 17에서이 작업을 수행 할 수 있습니다.

struct A { int a; };
struct B { B(int){} };

struct C : A {};
struct D : B {};

int main() {
    (void) C{2};
    (void) D{1};
}

우리는 생성자를 상속하지 않습니다. 17 ++ C에서 C하고 D있습니다 지금은 기본 클래스를 경우에도 집계합니다.

를 사용 {}하면 집계 초기화가 시작되고 매개 변수를 전송하지 않는 것은 외부에서 부모의 기본 생성자를 호출하는 것과 동일하게 해석됩니다.

예를 들어, 클래스 D를 다음과 같이 변경하여 집계 초기화를 비활성화 할 수 있습니다 .

struct B { protected: B(){} };

struct D : B {
    int b;
private:
    int c;
};

int main() {
    (void) D{}; // works!
}

이는 액세스 지정자가 다른 멤버가있는 경우 집계 초기화가 적용되지 않기 때문입니다.

Works를 사용하는 이유 = default는 사용자가 제공 한 생성자가 아니기 때문입니다. 이 질문에 대한 자세한 정보 .

참고 URL : https://stackoverflow.com/questions/47656093/changed-rules-for-protected-constructors-in-c17

반응형

'ProgramingTip' 카테고리의 다른 글

Docker- 컨테이너가 실행되고 있지 않습니다.  (0) 2020.12.05
Pythonic 방법은 무엇입니까?  (0) 2020.12.05
ThreadPool 대 작업  (0) 2020.12.05
사실과 이론의 차이?  (0) 2020.12.05
Angular의 빌드 및 실행 방법  (0) 2020.12.05