상속 : 'A'는 'B'의 액세스 할 수없는 기반입니다.


82
$ cat inheritance.cpp 
#include <iostream>

using namespace std;

class A { };
class B : private A { };

int main() {
    A* ab = new B;
}
$
$ g++ inheritance.cpp
inheritance.cpp: In function 'int main()':
inheritance.cpp:9: error: 'A' is an inaccessible base of 'B'
$

이 오류를 이해하지 못합니다.

내가 이해 하고이 자습서에서 확인 했듯이 private상속은의 구성원이 class B외부 세계에 표시되는 방식 만 변경해야합니다 .

개인 지정자는 class B여기서 멤버의 가시성을 변경하는 것 이상을 수행하고 있다고 생각합니다 .

  • 이 오류는 무엇이며 의미는 무엇입니까?
  • 기본적으로 C ++에서 이러한 유형의 코드를 허용하는 것이 잘못된 것은 무엇입니까? 완전히 무해 해 보입니다.

답변:


100

상속을 비공개로 설정하면 기본적으로 B가 A에서 상속한다는 사실조차도 외부 세계에 액세스하거나 볼 수없는 비공개라는 것입니다.

그것이 허용된다면 어떤 일이 일어날 지에 대한 장황한 논의를하지 않고, 단순한 사실은 그것이 허용되지 않는다는 것입니다. 파생 형식의 개체를 참조하기 위해 포인터를 기준으로 사용하려는 경우 공용 상속을 사용하는 데 거의 어려움이 있습니다.

개인 상속은 없습니다 반드시 (또는 보통)을 수행하도록 구성 Liskov 대체 원칙을 . 공용 상속은 파생 된 개체가 기본 클래스의 개체로 대체 될 수 있다고 주장하며 적절한 의미 체계 계속 생성됩니다. 그러나 개인 상속은 그것을 주장 하지 않습니다 . 개인 상속에 의해 암시되는 관계에 대한 일반적인 설명은 "다음으로 구현 됨"입니다.

공용 상속이란 파생 클래스가 기본 클래스의 모든 기능을 유지하고 잠재적으로 추가 기능을 추가한다는 것을 의미합니다. private 상속은 종종 그 반대를 의미합니다. 파생 클래스는 일반 기본 클래스를 사용하여 더 제한된 인터페이스로 무언가를 구현합니다.

예를 들어, C ++ 표준 라이브러리의 컨테이너가 템플릿이 아닌 상속을 사용하여 구현되었다고 가정 해 보겠습니다. 현재 시스템에서, std::dequestd::vector용기이며, std::stack보다 제한된 인터페이스를 제공하는 컨테이너 어댑터이다. 템플릿을 기반으로하기 때문에 또는에 std::stack대한 어댑터로 사용할 수 있습니다 .std::dequestd::vector

본질적으로 동일한 상속을 제공하려면 개인 상속을 사용할 std::stack것이므로 다음과 같습니다.

class stack : private vector {
    // ...
};

이 경우, 우리는 확실히 않습니다 하지 사용자가 우리를 조작 할 수 있도록하려면 stack그것 인 것처럼 vector. 그렇게하면 스택의 기대치를 위반할 수 있습니다 (예 : 사용자가 의도 한대로 순전히 스택과 같은 방식이 아니라 중간에 항목을 삽입 / 제거 할 수 있음). 우리는 기본적으로 사용하고있는 vector우리의 스택을 구현하는 편리한 방법으로하지만, (예를 들어) 우리의 구현 변경 한 경우 stack또는 (NO 기본 클래스에 대한 의존도와) 독립을 측면에서 그것을 다시 구현 std::deque, 우리는 할 수 없습니다 것을 원하는 클라이언트 코드에 영향을 미치기 위해 클라이언트 코드에 대해 이것은 특수한 다양한 벡터 (또는 데크)가 아닌 스택이어야합니다.


1
이것은 또한 적용됩니다protected
SubMachine

12

개인 상속은 클래스 B의 구성원이 외부 세계에 표시되는 방식 만 변경해야합니다.

그렇습니다. 그리고 만약

A* p = new B;

허용 된 후 어떤의 상속 된 멤버는 B단지함으로써, 외부에서 액세스 할 수 있습니다 A*. 그들은 개인적으로 상속되기 때문에 그 액세스는 불법이며 업 캐스트도 마찬가지입니다.


8

clang++ 약간 더 이해하기 쉬운 오류 메시지를 제공합니다.

example.cpp:9:13: error: cannot cast 'B' to its private base class 'A'
    A* ab = new B;
            ^
example.cpp:6:11: note: declared private here
class B : private A { };
          ^~~~~~~~~
1 error generated.

저는 C ++ 전문가는 아니지만 단순히 허용되지 않는 것 같습니다. 사양을 살펴보고 어떤 결과가 나오는지 살펴 보겠습니다.

편집 : 여기에 사양-섹션 4.10 포인터 변환 , 단락 3 의 관련 참조가 있습니다 .

유형의 prvalue "포인터 CV D " D클래스 타입은 타입의 prvalue "CV 포인터로 변환 할 수 BB가의베이스 클래스이다" D. 경우 B의 액세스 또는 모호한 기본 클래스입니다 D이 변환을 필요로하는 프로그램이 잘못 형성된다.


5

매우 간단합니다. A개인적으로 상속된다는 사실은 B확장 되는 사실이 A비밀이며 B"알고" 만 있음을 의미 합니다. 이것이 바로 사적 상속의 정의입니다.


4
내가 대체한다면 나는 매우 동일한 오류 private와 함께 protected.
하기 Lazer

2
과연. "보호됨"은 지식이의 B하위 클래스 (및 친구)로 제한됨을 의미합니다 B. " A* ab = new B;" C는의 하위 클래스였던 가상 클래스에서 합법적 입니다 B.
Ernest Friedman-Hill

3

개인 상속은 파생 클래스 외부에서 상속 정보가 숨겨 짐을 의미합니다. 즉, 파생 클래스를 기본 클래스로 캐스팅 할 수 없습니다. 관계는 호출자에게 알려지지 않습니다.


고마워,하지만 어떻게 든 말이 안돼. private유일한 사업은 회원들의 행동 방식을 통제하는 것입니다. 상속 정보가 숨겨지지 않으면 어떤 피해가 발생합니까?
하기 Lazer

1
개인 상속은 집계 / 구성의 한 형태입니다. 그것은 할 수있는 방법 없이, 기본 클래스의 속성을 있는 기본 클래스의 객체입니다. 그것이 당신이 원하는 것이 아니라면, 개인 상속은 당신을위한 것이 아닙니다. 그것이 작동하는 방식입니다.
tmpearce 2012 년

0

이것은 작동합니다

#include <iostream>

using namespace std;

class A{
    public:
        virtual void update() = 0;
};

class B: public A{
    public:
    virtual void update(){std::cout<<"hello";};
};

int main()
{
    A *a = new B();

    a->update();

    return 0;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.