C++
public
の、private
、およびprotected
継承の違いは何ですか?
SOで見つけたすべての質問は、特定のケースを扱っています。
C++
public
の、private
、およびprotected
継承の違いは何ですか?
SOで見つけたすべての質問は、特定のケースを扱っています。
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 が含まれます。それは単にアクセスの問題です。
保護された非公開継承の使用については、こちらを参照してください。
その質問に答えるために、まずメンバーのアクセサについて自分の言葉で説明したいと思います。すでにこれを知っている場合は、「次へ:」という見出しにスキップしてください。
私が認識している 3 つのアクセサーがあります: 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
Child
Child
Base
protected
のみが から継承していることを認識しています。Child
Base
private
1 人だけです。Child
継承の可視性を制限すると、あるクラスが別のクラスを継承していることをコードが認識できなくなります。派生クラスからベースクラスへの暗黙の変換は機能しません。また、ベースクラスから派生クラスへの暗黙的な変換も機能しstatic_cast
ません。
クラスのメンバー/フレンドのみがプライベート継承を参照でき、メンバー/フレンドと派生クラスのみが保護された継承を参照できます。
公開継承
IS-A 継承。ボタンはウィンドウであり、ウィンドウが必要な場所ならどこでもボタンを渡すことができます。
class button : public window { };
保護された継承
保護された実装の観点から。めったに役に立ちません。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!
}
};
私的遺産
の観点から実装されています。基本クラスの使用は、派生クラスを実装するためだけです。トレイトとサイズが重要な場合に役立ちます (関数のみを含む空のトレイトは、空の基本クラスの最適化を利用します)。ただし、多くの場合、封じ込めがより良い解決策です。文字列のサイズは重要であるため、ここでよく見られる使用法です。
template<typename StorageModel>
struct string : private StorageModel {
public:
void realloc() {
// uses inherited function
StorageModel::realloc();
}
};
一般会員
集計
class pair {
public:
First first;
Second second;
};
アクセサー
class window {
public:
int getWidth() const;
};
保護されたメンバー
派生クラスへの拡張アクセスの提供
class stack {
protected:
vector<element> c;
};
class window {
protected:
void registerClass(window_descriptor w);
};
プライベートメンバー
実装の詳細を保持する
class window {
private:
int width;
};
C スタイルのキャストでは、意図的に、定義された安全な方法で派生クラスを保護されたまたはプライベートな基本クラスにキャストしたり、他の方向にもキャストしたりできることに注意してください。コードが実装の詳細に依存する可能性があるため、これは絶対に避ける必要がありますが、必要に応じてこの手法を利用できます。
これら 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になります。z
x
より詳細な例:
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
すべての特性を継承するということですか?Super
Super
いいえ。そうではありません。
次のコードをコンパイルすると、メソッドにアクセスできないことを示すコンパイル エラーput
がget
表示されます。なんで?
可視性指定子を省略すると、コンパイラは、いわゆるプライベート継承を適用すると想定します。これは、すべてのパブリックスーパークラス コンポーネントがプライベートアクセスになることを意味し、プライベート スーパークラス コンポーネントにはまったくアクセスできなくなります。したがって、サブクラス内で後者を使用することは許可されていません。
以前に使用したアクセス ポリシーを保持することをコンパイラに通知する必要があります。
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
これは、基本クラスのパブリック メンバーが派生クラスからどのように公開されるかに関係しています。
litb が指摘しているように、パブリック継承は、ほとんどのプログラミング言語で見られる伝統的な継承です。つまり、「IS-A」関係をモデル化したものです。プライベート継承は、知る限り C++ に特有のものであり、「条件付きで実装」された関係です。つまり、派生クラスでパブリック インターフェイスを使用したいが、派生クラスのユーザーがそのインターフェイスにアクセスできないようにしたいということです。多くの人は、この場合、基本クラスを集約する必要があると主張しています。つまり、基本クラスをプライベートベースとして持つ代わりに、派生のメンバーを作成して、基本クラスの機能を再利用します。
Member in base class : Private Protected Public
継承タイプ :次 のように継承されたオブジェクト:
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
公開継承は、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
継承モデルを知っている人はいないと思います。少なくとも、説得力のある説明はまだ見たことがありません。
別のクラスからパブリックに継承する場合、誰もが継承していることを認識し、基本クラス ポインターを介して誰でもポリモーフィックに使用できます。
保護された継承を行うと、子クラスのみがポリモーフィックに使用できます。
非公開で継承すると、自分だけが親クラスのメソッドを実行できます。
これは基本的に、親クラスとの関係について残りのクラスが持っている知識を象徴しています
保護されたデータ メンバーは、クラスから継承する任意のクラスからアクセスできます。ただし、プライベート データ メンバーはできません。以下があるとしましょう:
class MyClass {
private:
int myPrivateMember; // lol
protected:
int myProtectedMember;
};
拡張機能内からこのクラスへの参照this.myPrivateMember
は機能しません。ただし、しthis.myProtectedMember
ます。値はまだカプセル化されているため、このクラスのインスタンス化が と呼ばれるmyObj
場合myObj.myProtectedMember
は機能しません。そのため、プライベート データ メンバーと機能が似ています。
概要:
継承する場合、(一部の言語では) データ メンバーの保護タイプを特定の方向に変更できます (例: protected から public へ)。
基本クラスのプライベート メンバーには、その基本クラスのメンバーのみがアクセスできます。
基本クラスのパブリック メンバーには、その基本クラスのメンバー、その派生クラスのメンバー、および基本クラスと派生クラスの外部にあるメンバーがアクセスできます。
基本クラスの保護されたメンバーには、基本クラスのメンバーだけでなく、その派生クラスのメンバーもアクセスできます。
プライベート: ベース
protected : ベース + 派生
public : ベース + 派生 + その他のメンバー
簡単な答えを見つけたので、今後の参考のために投稿することも考えました。
そのリンクから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
}
これは本質的に、派生クラスの基本クラスの public および protected メンバーのアクセス保護です。パブリック継承により、派生クラスは、ベースのパブリック メンバーと保護されたメンバーを参照できます。プライベート継承では、それはできません。保護されている場合、派生クラスとその派生クラスはそれらを見ることができます。