1143

C++publicの、private、およびprotected継承の違いは何ですか?

SOで見つけたすべての質問は、特定のケースを扱っています。

4

16 に答える 16

1623
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 が含まれます。それは単にアクセスの問題です。

保護された非公開継承の使用については、こちらを参照してください。

于 2009-09-03T11:27:56.297 に答える
1156

その質問に答えるために、まずメンバーのアクセサについて自分の言葉で説明したいと思います。すでにこれを知っている場合は、「次へ:」という見出しにスキップしてください。

私が認識している 3 つのアクセサーがあります: publicprotectedおよびprivate

させて:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • を認識しているものはすべて、 が含まれBaseていることも認識していBaseますpublicMember
  • Baseが含まれていることを認識しているのは、子 (およびその子) だけprotectedMemberです。
  • 誰も知らない。Base_privateMember

「認識している」とは、「の存在を認識し、アクセスできる」という意味です。

次:

パブリック、プライベート、および保護された継承でも同じことが起こります。から継承するクラスBaseとクラスを考えてみましょう。ChildBase

  • 継承が である場合、を認識し、から継承することも認識しているすべてpublicのもの。BaseChildChildBase
  • 継承が の場合、 とその子protectedのみが から継承していることを認識しています。ChildBase
  • 継承が の場合、継承を認識しているのはprivate1 人だけです。Child
于 2009-05-13T20:49:37.733 に答える
123

継承の可視性を制限すると、あるクラスが別のクラスを継承していることをコードが認識できなくなります。派生クラスからベースクラスへの暗黙の変換は機能しません。また、ベースクラスから派生クラスへの暗黙的な変換も機能し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 スタイルのキャストでは、意図的に、定義された安全な方法で派生クラスを保護されたまたはプライベートな基本クラスにキャストしたり、他の方向にもキャストしたりできることに注意してください。コードが実装の詳細に依存する可能性があるため、これは絶対に避ける必要がありますが、必要に応じてこの手法を利用できます。

于 2009-09-03T16:04:21.027 に答える
84

これら 3 つのキーワードは、可視性継承モデル を指定するために、まったく異なるコンテキストでも使用されます。

この表は、サブクラスが完全に定義されたときのコンポーネントへの結果的なアクセスを示す、コンポーネント宣言と継承モデルの可能な組み合わせをすべて集めたものです。

ここに画像の説明を入力

上の表は次のように解釈されます (最初の行を見てください)。

コンポーネントがpublicとして宣言され、そのクラスがpublicとして継承される場合、結果のアクセスpublicになります。

例:

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

 class Sub : private Super {};

 class Subsub : public Sub {};

クラスSubsubの変数p,qに対する結果のアクセスはnoneです。r

もう一つの例:

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

クラスSubyの変数へのアクセスは保護され、変数へのアクセスはnoneになります。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;
}

という名前のクラスのサブクラスである Sub という名前の定義済みクラス、SuperまたはそのSubクラスはクラスから派生していSuperます。このSubクラスは、新しい変数も新しい関数も導入しません。クラスが実際にクラスのオブジェクトのコピーになった後、クラスのオブジェクトはSubすべての特性を継承するということですか?SuperSuper

いいえ。そうではありません。

次のコードをコンパイルすると、メソッドにアクセスできないことを示すコンパイル エラーputget表示されます。なんで?

可視性指定子を省略すると、コンパイラは、いわゆるプライベート継承を適用​​すると想定します。これは、すべてのパブリックスーパークラス コンポーネントがプライベートアクセスになることを意味し、プライベート スーパークラス コンポーネントにはまったくアクセスできなくなります。したがって、サブクラス内で後者を使用することは許可されていません。

以前に使用したアクセス ポリシーを保持することをコンパイラに通知する必要があります。

class Sub : public Super { };

誤解しないでください。Superクラスのプライベート コンポーネント (ストレージ変数など) が、魔法のような方法でパブリック コンポーネントに変わるわけではありません。privateコンポーネントはprivateのままで、publicはpublicの ままです。

クラスのオブジェクトは、Subクラスから作成された古い兄弟と「ほぼ」同じことを行う場合がありますSuperサブクラスであるという事実は、クラスがスーパークラスのプライベート コンポーネントへのアクセスを失ったことも意味するため、「ほぼ」です。ストレージ変数を直接操作できるクラスのメンバー関数を作成することはできません。Sub

これは非常に深刻な制限です。回避策はありますか?

はい

3 番目のアクセス レベルはprotectedと呼ばれます。キーワード protected は、それでマークされたコンポーネントが、サブクラスのいずれかによって使用されたときにパブリック コンポーネントのように動作し、他の世界からはプライベート コンポーネントのように見えることを意味します。--これは、パブリックに継承されたクラス (この例の Super クラスなど) にのみ当てはまります--

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クラスに新しい機能を追加し、1 つの重要なことを行います。それは、 Super クラスからストレージ変数にアクセスすることです。

変数がプライベートとして宣言されている場合は不可能です。メイン関数スコープでは、変数はとにかく非表示のままなので、次のように書くと:

object.storage = 0;

コンパイラは、それがerror: 'int Super::storage' is protected.

最後に、最後のプログラムは次の出力を生成します。

storage = 101
于 2015-06-07T16:56:41.690 に答える
69

これは、基本クラスのパブリック メンバーが派生クラスからどのように公開されるかに関係しています。

  • public -> 基本クラスの public メンバーは public になります (通常はデフォルト)
  • 保護 -> 基本クラスのパブリック メンバーは保護されます
  • private -> 基本クラスの public メンバーは private になります

litb が指摘しているように、パブリック継承は、ほとんどのプログラミング言語で見られる伝統的な継承です。つまり、「IS-A」関係をモデル化したものです。プライベート継承は、知る限り C++ に特有のものであり、「条件付きで実装」された関係です。つまり、派生クラスでパブリック インターフェイスを使用したいが、派生クラスのユーザーがそのインターフェイスにアクセスできないようにしたいということです。多くの人は、この場合、基本クラスを集約する必要があると主張しています。つまり、基本クラスをプライベートベースとして持つ代わりに、派生のメンバーを作成して、基本クラスの機能を再利用します。

于 2009-05-13T20:49:19.607 に答える
37
Member in base class : Private   Protected   Public   

継承タイプ :次             のように継承されたオブジェクト

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public
于 2010-09-09T05:25:38.283 に答える
20

公開継承は、IS-A 関係をモデル化します。と

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

すべてD Bです。

プライベート継承は、IS-IMPLEMENTED-USING 関係 (またはそれが呼ばれるもの) をモデル化します。と

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

aDはaではありませんBが、すべての実装でそれDを使用しBます。プライベート継承は、代わりに包含を使用することで常に排除できます。

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

これDも、 を使用して実装できます。Bこの場合は、 を使用しb_ます。コンテインメントは、継承よりもタイプ間の緊密な結合が少ないため、一般的に優先されます。プライベート継承の代わりに包含を使用することは、プライベート継承ほど便利ではない場合があります。多くの場合、それは怠け者であることの言い訳です。

protected継承モデルを知っている人はいないと思います。少なくとも、説得力のある説明はまだ見たことがありません。

于 2009-09-03T12:34:26.367 に答える
10

別のクラスからパブリックに継承する場合、誰もが継承していることを認識し、基本クラス ポインターを介して誰でもポリモーフィックに使用できます。

保護された継承を行うと、子クラスのみがポリモーフィックに使用できます。

非公開で継承すると、自分だけが親クラスのメソッドを実行できます。

これは基本的に、親クラスとの関係について残りのクラスが持っている知識を象徴しています

于 2009-09-03T11:27:55.203 に答える
9

保護されたデータ メンバーは、クラスから継承する任意のクラスからアクセスできます。ただし、プライベート データ メンバーはできません。以下があるとしましょう:

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

拡張機能内からこのクラスへの参照this.myPrivateMemberは機能しません。ただし、しthis.myProtectedMemberます。値はまだカプセル化されているため、このクラスのインスタンス化が と呼ばれるmyObj場合myObj.myProtectedMemberは機能しません。そのため、プライベート データ メンバーと機能が似ています。

于 2009-05-13T20:57:10.703 に答える
7

概要:

  • 非公開: クラス内以外は誰も見ることができません
  • 保護: プライベート + 派生クラスはそれを見ることができます
  • パブリック: 世界中の人が見ることができます

継承する場合、(一部の言語では) データ メンバーの保護タイプを特定の方向に変更できます (例: protected から public へ)。

于 2009-05-13T20:58:28.140 に答える
7

プライベート:

基本クラスのプライベート メンバーには、その基本クラスのメンバーのみがアクセスできます。

公衆:

基本クラスのパブリック メンバーには、その基本クラスのメンバー、その派生クラスのメンバー、および基本クラスと派生クラスの外部にあるメンバーがアクセスできます。

保護中:

基本クラスの保護されたメンバーには、基本クラスのメンバーだけでなく、その派生クラスのメンバーもアクセスできます。


要するに:

プライベート: ベース

protected : ベース + 派生

public : ベース + 派生 + その他のメンバー

于 2010-01-06T14:04:59.367 に答える
4

簡単な答えを見つけたので、今後の参考のために投稿することも考えました。

そのリンクから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
}
于 2015-02-24T10:05:09.517 に答える
3

これは本質的に、派生クラスの基本クラスの public および protected メンバーのアクセス保護です。パブリック継承により、派生クラスは、ベースのパブリック メンバーと保護されたメンバーを参照できます。プライベート継承では、それはできません。保護されている場合、派生クラスとその派生クラスはそれらを見ることができます。

于 2009-05-13T20:51:43.597 に答える