개인, 공용 및 보호 된 상속의 차이점


답변:


1064

이 질문에 대답하기 위해 먼저 회원의 접근자를 내 말로 설명하고 싶습니다. 이미 알고 있다면 "다음 :"으로 넘어가십시오.

거기에 제가 알고 세 가지 접근은 다음과 같습니다 public, protected그리고 private.

허락하다:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • 알고있는 모든 것은 Base또한 Base포함하는 것을 알고 있습니다 publicMember.
  • 만 어린이들 (자녀)은 알고 있습니다 Base포함되어 있습니다 protectedMember.
  • 아무도하지만 Base알고 없습니다 privateMember.

"알다"는 것은 "존재 함을 인정하고 따라서 접근 할 수 있음"을 의미합니다.

다음:

공개, 개인 및 보호 된 상속에서도 마찬가지입니다. 에서 상속되는 클래스 Base와 클래스 Child를 생각해 봅시다 Base.

  • 상속이 public인지 Base하고 알고있는 모든 것이 상속 ChildChild받는 경우 Base.
  • 상속이 protected유일한 Child경우에 그 하위 항목은 상속을 인식합니다 Base.
  • 상속이 private인 경우 상속을 Child알고있는 사람 외에는 아무도 없습니다 .

182
C ++의 가시성이 객체 대신 클래스를 기반으로한다는 몇 가지 단어를 추가하고 싶습니다. 즉, 동일한 클래스의 객체가 제한없이 서로의 개인 필드에 액세스 할 수 있음을 의미합니다.
Zhe Chen

48
이것을 이해하는 데 어려움이 있다면 Kirill V. Lyadvinsky의 답변을 읽은 다음 다시 와서 읽으십시오.
Vivandiere

6
이것은 대부분의 경우 상속 SomeBase하는 방식이 익명의 type 멤버를 작성하는 하드 코딩 된 방법과 유사한 방법을 보여주는 또 다른 사례입니다 SomeBase. 다른 멤버와 마찬가지로이 액세스 지정자는 외부 액세스에 대해 동일한 제어를 수행합니다.
underscore_d

1
@ZheChen 개인 필드 연령의 Person 클래스의 Tom과 Jerry 객체가 있으면 Tom을 사용하여 Jerry의 나이에 어떻게 액세스하고 수정합니까?
gen

2
" '상속'에 대한 인식"의 의미를 설명해 주시겠습니까? 나는 "나는 이것에 접근 할 수 없다"는 것을 이해할 수 있지만 "A가 B로부터 상속 받았다는 것을 알고있다"고 말할 때 나는 그것을 얻지 못합니다.
neilxdims

1458
class A 
{
public:
    int x;
protected:
    int y;
private:
    int z;
};

class B : public A
{
    // x is public
    // y is protected
    // z is not accessible from B
};

class C : protected A
{
    // x is protected
    // y is protected
    // z is not accessible from C
};

class D : private A    // 'private' is default for classes
{
    // x is private
    // y is private
    // z is not accessible from D
};

중요 참고 : 클래스 B, C 및 D는 모두 변수 x, y 및 z를 포함합니다. 접근의 문제 일뿐입니다.

보호 및 개인 상속 사용에 대해서는 여기를 참조하십시오 .


35
Anzurio가 작성한 것은 바로 아래의 답변과 함께 클릭 만되었습니다. Плус 1.
Iwillnotexist Idonotexist

2
이것이 어떻게 작동했는지에 대한 나의 이해는 너무 멀리 떨어져있었습니다! 명확하게 해주셔서 감사합니다.
tjwrona1992

이것을 이해하는 데 시간이 걸렸습니다. 그러나 지금은 분명하다. 감사!
Chan Kim

115

상속의 가시성을 제한하면 코드에서 일부 클래스가 다른 클래스를 상속 함을 알 수 없습니다. 파생에서 기본으로의 암시 적 변환은 작동하지 않으며 기본에서 파생으로의 암시 적 변환도 작동 static_cast하지 않습니다.

클래스의 멤버 / 친구 만 개인 상속을 볼 수 있으며 멤버 / 친구 및 파생 클래스 만 보호 된 상속을 볼 수 있습니다.

공공 상속

  1. IS-A 상속. 버튼은 윈도우이며, 윈도우가 필요한 곳이면 버튼도 전달할 수 있습니다.

    class button : public window { };

보호 된 상속

  1. 기간 내에 보호됩니다. 거의 유용하지 않습니다. boost::compressed_pair빈 클래스에서 파생되고 빈 기본 클래스 최적화를 사용하여 메모리를 절약하는 데 사용됩니다 (아래 예에서는 템플릿을 사용하여 해당 지점을 계속 유지하지 않음).

    struct empty_pair_impl : protected empty_class_1 
    { non_empty_class_2 second; };
    
    struct pair : private empty_pair_impl {
      non_empty_class_2 &second() {
        return this->second;
      }
    
      empty_class_1 &first() {
        return *this; // notice we return *this!
      }
    };
    

개인 상속

  1. 이용 약관. 기본 클래스의 사용법은 파생 클래스를 구현하기위한 것입니다. 특성과 크기가 중요한 경우에 유용합니다 (함수 만 포함 된 빈 특성은 ​​빈 기본 클래스 최적화를 사용합니다). 그러나 종종 격리 가 더 나은 솔루션입니다. 문자열의 크기는 매우 중요하므로 여기에서 자주 볼 수 있습니다.

    template<typename StorageModel>
    struct string : private StorageModel {
    public:
      void realloc() {
        // uses inherited function
        StorageModel::realloc();
      }
    };
    

공개 회원

  1. 골재

    class pair {
    public:
      First first;
      Second second;
    };
    
  2. 접근 자

    class window {
    public:
        int getWidth() const;
    };
    

보호 회원

  1. 파생 클래스에 대한 향상된 액세스 제공

    class stack {
    protected:
      vector<element> c;
    };
    
    class window {
    protected:
      void registerClass(window_descriptor w);
    };
    

개인 회원

  1. 구현 세부 사항 유지

    class window {
    private:
      int width;
    };
    

C 스타일 캐스트는 정의 된 안전한 방식으로 파생 클래스를 보호 또는 개인 기본 클래스로 캐스트하고 다른 방향으로도 캐스트 할 수 있습니다. 구현 세부 사항에 따라 코드를 만들 수 있기 때문에 모든 비용을 피해야하지만 필요한 경우이 기술을 사용할 수 있습니다.


7
Scott Myers는 (그의 물건을 좋아하는만큼) 일반적인 혼란에 대해 많은 답을 가지고 있다고 생각합니다. 나는 그의 IS-A와 IS-IMPLEMENTED-IN-TERMS-OF에 대한 그의 비유가 진행되고있는 것으로 충분하다고 생각합니다.
DangerMouse

65

이 세 키워드는 또한 완전히 다른 상황에서 가시성 상속 모델 을 지정하는 데 사용됩니다 .

이 테이블은 서브 클래스가 완전히 정의 될 때 컴포넌트에 대한 결과 액세스를 나타내는 컴포넌트 선언 및 상속 모델의 가능한 모든 조합을 수집합니다.

여기에 이미지 설명을 입력하십시오

위의 표는 다음과 같이 해석됩니다 (첫 번째 행을보십시오).

구성 요소가되는 경우 선언 으로 대중 과 그 클래스가되어 상속 으로 공공 결과 액세스 입니다 공공 .

예를 들면 :

 class Super {
    public:      int p;
    private:     int q;
    protected:   int r;
 };

 class Sub : private Super {};

 class Subsub : public Sub {};

변수에 대한 결과 액세스 p, q, r수업 시간에 Subsub는 없다 아무도 .

또 다른 예:

class Super {
    private:     int x;
    protected:   int y;
    public:      int z;
 };
class Sub : protected Super {};

Sub 클래스의 변수 y에 대한 결과 액세스 는 보호 되며 variable 에 대한 액세스 는 없습니다 .zx

더 자세한 예 :

class Super {
private:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};
int main(void) {
    Super object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

이제 서브 클래스를 정의하자 :

class Sub : Super { };

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

명명 된 클래스의 서브 클래스 Super또는 해당 Sub클래스 의 서브 클래스 인 Sub이라는 정의 된 클래스는 클래스 에서 파생됩니다 Super. 이 Sub클래스는 새로운 변수 나 새로운 함수를 도입하지 않습니다. 그것은 Sub클래스의 객체가 Super클래스가 실제로 Super클래스 객체 의 사본이 된 후에 모든 특성을 상속 한다는 것을 의미합니까 ?

없음 . 그렇지 않습니다.

다음 코드를 컴파일하면 컴파일 오류 putget메소드에 액세스 할 수 없다는 컴파일 오류 만 표시 됩니다. 왜?

가시성 지정자를 생략하면 컴파일러는 소위 개인 상속 을 적용한다고 가정합니다 . 이는 모든 퍼블릭 슈퍼 클래스 컴포넌트가 프라이빗 액세스 로 바뀌고 프라이빗 슈퍼 클래스 컴포넌트는 전혀 액세스 할 수 없음을 의미합니다. 따라서 서브 클래스 내에서 후자를 사용할 수 없음을 의미합니다.

우리는 이전에 사용 된 액세스 정책을 보존하고 싶다고 컴파일러에 알려야합니다.

class Sub : public Super { };

오해하지 마십시오 : 스토리지 변수와 같은 Super 클래스의 개인 구성 요소가 다소 마술적인 방식으로 공개 구성 요소로 바뀐다는 의미는 아닙니다. 비공개 구성 요소는 비공개로 유지 되며 공개공개 상태로 유지 됩니다.

Sub클래스의 객체는 클래스에서 생성 된 이전 형제와 같은 것을 "거의"수행 할 수 있습니다 Super. "거의" 서브 클래스라는 사실은 클래스가 슈퍼 클래스의 개인 컴포넌트에 대한 액세스 권한을 상실 했음을 의미하기 때문 입니다. Sub저장 변수를 직접 조작 할 수 있는 클래스 의 멤버 함수를 작성할 수 없습니다 .

이것은 매우 심각한 제한 사항입니다. 해결 방법이 있습니까?

.

세 번째 액세스 수준을 protected 라고 합니다. protected 키워드 는 서브 클래스에서 사용될 때이 컴포넌트로 표시된 컴포넌트 가 공용 컴포넌트 처럼 작동하며 다른 세계에서는 개인 컴포넌트 처럼 보입니다 . - 이 (우리의 예에서 슈퍼 클래스와 같은)만을 공개적으로 상속 클래스 마찬가지입니다 -

class Super {
protected:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};

class Sub : public Super {
public:
    void print(void) {cout << "storage = " << storage;}
};

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get() + 1);
    object.print();
    return 0;
}

예제 코드에서 알 수 있듯이 Sub클래스에 대한 새로운 기능 이며 한 가지 중요한 작업 을 수행합니다. Super 클래스에서 스토리지 변수에 액세스합니다 .

변수가 private으로 선언되면 불가능합니다. 기본 함수 범위에서 변수는 어쨌든 숨겨져 있으므로 다음과 같이 작성하면 다음과 같습니다.

object.storage = 0;

컴파일러는 그것이임을 알려줍니다 error: 'int Super::storage' is protected.

마지막으로 마지막 프로그램은 다음과 같은 출력을 생성합니다.

storage = 101

4
수정 자 부족을 언급 한 첫 번째 방법은 (Class : SuperClass에서와 같이) 개인용입니다. 이것은 철저한 설명과 함께 다른 사람들이 빠뜨린 중요한 부분입니다. +1

2
과잉 IMO이지만 처음에 테이블을 좋아합니다.
cp.engr

63

기본 클래스의 공개 멤버가 파생 클래스에서 노출되는 방법과 관련이 있습니다.

  • 공개-> 기본 클래스의 공개 멤버는 공개 (일반적으로 기본값)입니다.
  • protected-> 기본 클래스의 공개 멤버가 보호됩니다
  • 비공개-> 기본 클래스의 공개 멤버는 비공개입니다

litb가 지적했듯이 공개 상속은 대부분의 프로그래밍 언어에서 볼 수있는 전통적인 상속입니다. 그것은 "IS-A"관계를 모형화 한 것입니다. C ++ 특유의 AFAIK 인 사유 상속은 "기간 내에 구현 된"관계입니다. 즉 , 파생 클래스에서 공용 인터페이스 를 사용 하려고 하지만 파생 클래스의 사용자가 해당 인터페이스에 액세스하지 못하도록해야합니다. 많은 경우,이 경우 기본 클래스를 개인 기본으로 사용하는 대신 기본 클래스를 집계해야 기본 클래스의 기능을 재사용하기 위해 파생 된 멤버를 작성해야합니다.


13
"공개 : 모든 사람이 상속을 볼 수있다"고 말하는 것이 좋습니다. protected : 상속은 파생 클래스와 친구들 만 볼 수 있습니다 ","비공개 : 상속은 클래스 자체와 친구들 만 볼 수 있습니다. " IS-A 관계는 보이지 않을 수 있습니다
Johannes Schaub-litb

4
내가 개인 상속을 사용한 것은 Doug T가 설명한 것, 즉 "파생 클래스에서 퍼블릭 인터페이스를 사용하고 싶지만 파생 클래스의 사용자가 해당 인터페이스에 액세스하는 것을 원하지는 않는다"는 것입니다. 기본적으로 이전 인터페이스를 봉인하고 파생 클래스를 통해 다른 인터페이스를 노출하는 데 사용했습니다.
Rich

36
Member in base class : Private   Protected   Public   

상속 유형 :              상속 된 객체 :

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public

23
오해의 소지가 있습니다. 기본 클래스의 개인 구성원은 일반 개인 클래스 구성원과는 상당히 다르게 작동합니다. 파생 클래스에서는 전혀 액세스 할 수 없습니다. 세 개의 "비공개"열이 "접근 할 수 없음"열이어야한다고 생각합니다. 이 질문에 대한 Kirill V. Lyadvinsky의 답변을 참조하십시오.
Sam Kauffman

27

1) 공공 상속 :

ㅏ. 파생 클래스에서는 기본 클래스의 비공개 멤버에 액세스 할 수 없습니다.

비. 기본 클래스의 보호 멤버는 파생 클래스에서 보호됩니다.

씨. 기본 클래스의 공개 멤버는 파생 클래스에서 공개로 유지됩니다.

따라서 다른 클래스는 파생 클래스 개체를 통해 Base 클래스의 공용 멤버를 사용할 수 있습니다.

2) 상속 상속 :

ㅏ. 파생 클래스에서는 기본 클래스의 비공개 멤버에 액세스 할 수 없습니다.

비. 기본 클래스의 보호 멤버는 파생 클래스에서 보호됩니다.

씨. Base 클래스의 공개 멤버도 파생 클래스의 보호 멤버가됩니다.

따라서 다른 클래스는 파생 클래스 개체를 통해 Base 클래스의 공용 멤버를 사용할 수 없습니다. 그러나 Derived의 서브 클래스에서 사용할 수 있습니다.

3) 개인 상속 :

ㅏ. 파생 클래스에서는 기본 클래스의 비공개 멤버에 액세스 할 수 없습니다.

비. 기본 클래스의 보호 및 공개 멤버는 파생 클래스의 개인 멤버가됩니다.

따라서 파생 클래스에서 개인 클래스이므로 파생 클래스 개체를 통해 다른 클래스에서 Base 클래스의 멤버에 액세스 할 수 없습니다. 따라서 파생 클래스의 하위 클래스조차도 액세스 할 수 없습니다.


20

공공 상속은 IS-A 관계를 모델링합니다. 와

class B {};
class D : public B {};

모두 D 는입니다 B .

개인 상속은 IS-IMPLEMENTED-USING 관계 (또는 소위 무엇이든)를 모델링합니다. 와

class B {};
class D : private B {};

a는 D이다 하지B 하지만, 모든이 D의를 사용하여 B구현에. 비공개 상속은 항상 대신에 포함을 사용하여 제거 할 수 있습니다.

class B {};
class D {
  private: 
    B b_;
};

이것은 D역시 사용하여 구현 될 수있다 B자사를 사용하여,이 경우 b_. 포함은 상속보다 유형 간의 결합이 덜 엄격하므로 일반적으로 선호됩니다. 개인 상속 대신 격리를 사용하는 것이 개인 상속만큼 편리하지 않은 경우가 있습니다. 종종 그것은 게으른 것에 대한 절름발이입니다.

나는 protected상속 모델 이 무엇인지 아는 사람이 없다고 생각 합니다. 적어도 나는 설득력있는 설명을 보지 못했습니다.


어떤 사람들은 관계라고 말합니다. 의자를 망치로 사용하는 것과 같습니다. 여기 의자 : 보호 망치
4951

개인 상속 대신 격리를 사용할 때 개인 상속만큼 편리하지 않습니까? 예를 사용하여 설명해 주시겠습니까?
소멸자

@Pravasi : D에서 비공개로 파생 된 경우의 D가상 기능을 재정의 할 수 있습니다 B. (예를 들어 B옵저버 인터페이스 인 경우 모든 사용자가 옵저버 로 사용할 수없는 상태에서 인터페이스를 D구현 this하고 많은 인터페이스를 필요로하는 함수에 전달할 수 있습니다 D.) 또한 을 수행하여 인터페이스에서 D멤버를 선택적으로 B사용할 수 있습니다 using B::member. 두 B멤버 모두 멤버 인 경우 구현하기에 구문 적으로 불편합니다 .
sbi

@ sbi : 오래된 것입니다 ...하지만 격리는 CRTP 및 / 또는 가상의 경우 아무런 의미가 없습니다 (주석에서 올바르게 설명했듯이-B가 추상적 인 방법을 가지고 있다면 격리로 모델링 할 수 없음을 의미합니다 만질 수 없습니다). protected상속 virtual기본 클래스와 protectedctor에 유용하다는 것을 알았습니다 .struct CommonStuff { CommonStuff(Stuff*) {/* assert !=0 */ } }; struct HandlerMixin1 : protected virtual CommonStuff { protected: HandlerMixin1() : CommonStuff(nullptr) {} /*...*/ }; struct Handler : HandlerMixin1, ... { Handler(Stuff& stuff) : CommonStuff(&stuff) {} };
lorro

11

다른 클래스에서 공개적으로 상속 받으면 모두가 자신이 상속한다는 것을 알고 기본 클래스 포인터를 통해 누구나 다형성으로 사용할 수 있습니다.

당신이 안전하게 상속한다면, 당신의 자녀 클래스 만이 당신을 다형성 적으로 사용할 수있을 것입니다.

당신이 개인적으로 상속한다면 당신 자신 만이 부모 클래스 메소드를 실행할 수있을 것입니다.

기본적으로 나머지 수업에서 부모님과의 관계에 대한 지식을 상징합니다.


9

보호 된 데이터 멤버는 클래스에서 상속 된 모든 클래스에서 액세스 할 수 있습니다. 그러나 개인 데이터 멤버는 할 수 없습니다. 우리가 다음을 가지고 있다고 가정 해 봅시다.

class MyClass {
    private:
        int myPrivateMember;    // lol
    protected:
        int myProtectedMember;
};

확장 프로그램 내에서이 클래스까지는 참조 this.myPrivateMember가 작동하지 않습니다. 그러나 this.myProtectedMember것입니다. 값은 여전히 우리가 호출이 클래스의 인스턴스가 그렇다면, 캡슐화 myObj한 후, myObj.myProtectedMember이 개인 데이터 멤버와 기능이 유사하다, 그래서하지 않습니다 일을.


8
Accessors    | Base Class | Derived Class | World
—————————————+————————————+———————————————+———————
public       |      y     |       y       |   y
—————————————+————————————+———————————————+———————
protected    |      y     |       y       |   n
—————————————+————————————+———————————————+———————
private      |            |               |    
  or         |      y     |       n       |   n
no accessor  |            |               |

y: accessible
n: not accessible

자바 에 대한 예제를 기반으로 ... 천 단어의 가치가있는 작은 테이블을 생각합니다 :)


자바는 공공 상속만을 가지고있다
Zelldon

이것은 자바에 대해 말할 주제는 아니지만 NO입니다. 당신은 틀 렸습니다 ... 자세한 내용은 위 답변의 링크를 따르십시오
Enissay

java를 언급 했으므로 주제입니다. 그리고 귀하의 예는 jaca에서 사용되는 지정자를 처리합니다. 문제는 Java에는 존재하지 않는 상속에 대한 지정자에 관한 것입니다. 슈퍼 클래스의 필드가 퍼블릭이고 상속이 프라이빗 인 경우 필드는 서브 클래스 내에서만 가능합니다. 외부에서 서브 클래스가 수퍼 클래스를 확장하는지 여부는 표시되지 않습니다. 그러나 테이블은 필드 및 메소드의 지정자 만 설명합니다.
Zelldon

7

요약:

  • 비공개 : 수업 내를 제외하고는 아무도 볼 수 없습니다.
  • 보호 : 개인 + 파생 클래스가 볼 수 있습니다
  • 공개 : 세상은 그것을 볼 수 있습니다

상속 할 때 (일부 언어로) 데이터 멤버의 보호 유형을 특정 방향으로 (예 : 보호에서 공개로) 변경할 수 있습니다.


6

은밀한:

기본 클래스의 개인 멤버는 해당 기본 클래스의 멤버 만 액세스 할 수 있습니다.

공공의:

기본 클래스의 공용 멤버는 해당 기본 클래스의 멤버, 파생 클래스의 멤버 및 기본 클래스 및 파생 클래스 외부에있는 멤버가 액세스 할 수 있습니다.

보호 :

기본 클래스의 보호 된 멤버는 기본 클래스의 멤버와 파생 클래스의 멤버가 액세스 할 수 있습니다.


한마디로 :

개인 : 기본

보호 : 기본 + 파생

공개 : 기본 + 파생 + 다른 멤버


5

나는 쉬운 대답을 찾았으므로 나중에 참조 할 수 있도록 게시 할 생각을했습니다.

링크 http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/에서

class Base
{
public:
    int m_nPublic; // can be accessed by anybody
private:
    int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)
protected:
    int m_nProtected; // can be accessed by Base member functions, or derived classes.
};

class Derived: public Base
{
public:
    Derived()
    {
        // Derived's access to Base members is not influenced by the type of inheritance used,
        // so the following is always true:

        m_nPublic = 1; // allowed: can access public base members from derived class
        m_nPrivate = 2; // not allowed: can not access private base members from derived class
        m_nProtected = 3; // allowed: can access protected base members from derived class
    }
};

int main()
{
    Base cBase;
    cBase.m_nPublic = 1; // allowed: can access public members from outside class
    cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class
    cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class
}

3

기본적으로 파생 클래스에서 기본 클래스의 공용 멤버와 보호 멤버의 액세스 보호입니다. 공개 상속을 통해 파생 클래스는 공개 및 보호 된 기본 멤버를 볼 수 있습니다. 개인 상속으로 할 수 없습니다. protected를 사용하면 파생 클래스와이 클래스에서 파생 된 모든 클래스를 볼 수 있습니다.

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