18

私は C++ の初心者で、C/C#/Objective-C などのオブジェクト指向言語について長年の経験があります。今、私はC++を学んでいます。

私はこの C++ コードを見ました:

    class World : public State
    {
    };

Worldクラスはクラスをパブリックに継承しているようStateです。公開サブクラス化? わかりにくいです。

この機能のコンセプトは何ですか? そして、これはいつ役に立ちますか、または必要ですか?

4

4 に答える 4

21

キーワードが必要なのは、publicキーワード で定義されたクラスclassの場合、デフォルトのアクセス修飾子 (データ メンバー、メンバー関数、基本クラスのすべて) がprivate. そう

class World : State {};

以下と同じです:

class World : private State {};

それはおそらくあなたが望むものではありません-それは、基本クラスが class 内でのみアクセスできることを意味しますWorld。部外者は、継承が存在することをまったく「知りません」。

キーワードstructで定義されたクラスの場合、デフォルトのアクセス修飾子はpublicであるため、次のように記述できます。

struct World : State {};

そして、継承を持つ他のすべての言語のように見え、動作するものを手に入れます。しかし、structキーワードと、それがクラスを定義するという事実は、実際には C との互換性のためだけにあります。デフォルトのパブリック アクセシビリティを取得するためだけに使用することを推奨する C++ スタイル ガイドは多くありません。 POD であるクラス、またはおそらくメンバー関数をまったく持たないクラスのみ。

そもそもなぜ C++ にプライベート継承があるのか​​というと、ほとんどの場合、プライベート継承は構成の形式です。通常の構成:

class World {
    State state;
  public:
    void foo() {
        state.bar();
        state.baz();
        and so on
    }
};

つまり、World クラスはそれが State を使用して実装されていることを認識していますが、外部の世界は World がどのように実装されているかを認識していません。

対。

class World : private State {
  public:
    void foo() {
        bar();
        baz();
        and so on
    }
};

つまり、クラス World はそれが State であることによって実装されていることを知っていますが、外部の世界はそれがどのように実装されているかを知りません。ただし、たとえばusing State::bar;、World の定義の public 部分を配置することにより、State のインターフェイスの一部を選択的に公開できます。その効果は、World で苦労して関数 (または複数のオーバーロード) を作成したかのようで、それぞれが State の同じ関数に委任されます。

ただし、入力を避ける以外に、private 継承の一般的な用途の 1 つは、クラスStateが空の場合、つまりデータ メンバーがない場合です。次に、それが のメンバーであるWorld場合は、ある程度のスペースを占有する必要があります (確かに、オブジェクトのレイアウトによっては、これは単にパディングになるスペースである可能性があるため、必ずしも のサイズが大きくなるとは限りませんWorld)。ただし、それが基本クラスの場合は、 「空の基本クラスの最適化」と呼ばれるものが始まり、サイズがゼロになる可能性があります。多くのオブジェクトを作成している場合、これは問題になる可能性があります。プライベート継承は最適化を可能にしますが、外部の世界は継承を認識しないため、「is-a」関係を推測しません。

それはかなり細かい違いです-疑わしい場合は、明示的な構成を使用してください。入力を節約するために継承を導入することは、予期しない結果が生じるまでは非常にうまくいきます。

于 2011-01-22T15:03:54.020 に答える
7

万一に備えて

class World: private State
{
};

プライベート継承とは、 のすべてpublicprotectedメンバーStateが に継承されWorld、 になることを意味しますprivateStateこれにより内部が密閉されWorldます。を継承するクラスはWorld、 の機能にアクセスできませんState

于 2011-01-22T15:04:07.883 に答える
3

プライベートだと思う根拠は?そこには public と表示されています。これは、パブリックにサブクラス化していることを意味します。

それはさておき、プライベートおよび保護された継承が行うことは、すべてのメンバー変数が少なくともプライベートまたは保護されたアクセシビリティで継承される関数であることを除いて、パブリック継承と同じです。たとえばState、パブリック メンバー関数 'foo()' がある場合、'World' ではプライベートになります。

これは実際にはめったに使用されませんが、目的があります。私が見た最も一般的な使用法は、継承による構成です。つまり、"is a" ではなく "has a" 関係が必要です (通常、パブリック継承で得られます)。クラスをプライベートに継承することで、そのすべての変数とメソッドを取得できますが、それらを外部に公開することはありません。

コンポジションにプライベート継承を使用する利点の 1 つは、空の基本クラスの最適化 (EBCO) にあります。すべての変数は一意のアドレスを持つ必要があるため、通常の構成を使用すると、空のクラスのメンバー オブジェクトを使用しても少なくとも 1 バイトは使用されます。構成したいオブジェクトを個人的に継承する場合、それは適用されず、メモリの損失に苦しむことはありません。

例えば

class Empty { };

class Foo
{
    int foo;
    Empty e;
};

class Bar : private Empty
{
    int foo;
};

ここでsizeof(Foo)は、おそらく 5 にsizeof(Bar)なりますが、基本クラスが空のため 4 になります。

于 2011-01-22T15:03:02.473 に答える
1

祖先クラスの名前の前の public/protected/private キーワードは、祖先からのメンバーの望ましい可視性を示します。プライベート継承では、子孫は先祖から実装のみを継承し、インターフェイスは継承しません。

class A {
public:
  void foo();
};

class B : private A {
public:
  void bar();
};

void B::bar()
{
  foo();  // can access foo()
}

B b;
b.foo(); // forbidden
b.bar(); // allowed

一般に、継承は実装の再利用のみに使用すべきではないため、パブリック継承を使用する必要があります (これはプライベート継承が行うことです)。

于 2011-01-22T15:06:04.580 に答える