web-dev-qa-db-ja.com

C ++でプライベートまたは保護された継承が実際に必要なのはなぜですか?

C++では、基本クラスからprivate/protectedを継承したい場合は考えられません。

class Base;
class Derived1 : private Base;
class Derived2 : protected Base;

本当に便利ですか?

57
Gal Goldman

基本クラスの一部のメンバーにアクセスしたいが、クラスインターフェイスでそれらを公開したくない場合に便利です。プライベート継承は、何らかの構成として見ることもできます。 C++ faq-lite は、このステートメントを説明するために次の例を示します。

class Engine {
 public:
   Engine(int numCylinders);
   void start();                 // Starts this Engine
};

class Car {
  public:
    Car() : e_(8) { }             // Initializes this Car with 8 cylinders
    void start() { e_.start(); }  // Start this Car by starting its Engine
  private:
    Engine e_;                    // Car has-a Engine
};

同じセマンティックを取得するには、次のようにcarクラスを記述することもできます。

class Car : private Engine {    // Car has-a Engine
 public:
   Car() : Engine(8) { }         // Initializes this Car with 8 cylinders
   using Engine::start;          // Start this Car by starting its Engine
}; 

ただし、この方法にはいくつかの欠点があります。

  • あなたの意図ははるかに明確ではありません
  • 虐待的な多重継承につながる可能性があります
  • 保護されたメンバーにアクセスできるため、Engineクラスのカプセル化が解除されます
  • engine仮想メソッドをオーバーライドできます。これは、目的が単純な構成である場合は望ましくないものです
44
Luc Touraille

プライベートは非常に多くの状況で役立ちます。それらの1つだけがポリシーです。

部分テンプレートテンプレートの特殊化は、この設計問題の答えですか?

便利なもう1つの機会は、コピーと割り当てを禁止することです。

struct noncopyable {
    private:
    noncopyable(noncopyable const&);
    noncopyable & operator=(noncopyable const&);
};

class my_noncopyable_type : noncopyable {
    // ...
};

ユーザーがオブジェクトへのnoncopyable*型のポインターを持つことを望まないため、プライベートに派生します。これは、コピー不可だけでなく、他の多くのそのようなクラスにも当てはまります(ポリシーが最も一般的です)。

公開継承モデルIS-A。
非パブリック継承モデルIS-IMPLEMENTED-IN-TERMS-OF。
包含モデルHAS-Aは、IS-IMPLEMENTED-IN-TERMS-OFと同等です。

トピックのサッター 。彼は、実装の詳細のために封じ込めよりも非公開継承を選択する場合を説明します。

15
Greg Rogers

プライベート継承は、主に間違った理由で使用されます。以前の回答で示されているように、人々はそれをIS-IMPLEMENTED-IN-TERMS-OFに使用しますが、私の経験では、クラスから継承するよりもコピーを保持する方が常にクリーンです。別の以前の回答、CBigArrayに関するものは、このアンチパターンの完璧な例を提供します。

Has-aが「protected」の熱心な使用のために機能しない場合があるかもしれないことを理解していますが、新しいクラスを壊すよりも壊れたクラスを修正する方が良いです。

3
Arkadiy

たとえば、クラスのインターフェースではなく実装を再利用し、かつその仮想関数をオーバーライドする場合。

3

私はある時点でプライベート継承と保護された継承の両方を使用しました。

プライベート継承は、基本クラスの動作を持たせ、その機能をオーバーライドできるようにしたいが、全世界がそれを認識して使用したくない場合に役立ちます。関数がそのインターフェイスを返すようにすることで、プライベートに派生したクラスのインターフェイスを引き続き使用できます。また、プライベートインターフェイスを使用して自分自身を登録できるので、コールバックをリッスンするように自分で登録できる場合にも役立ちます。

保護された継承は、別のクラスから有用な機能を派生させる基本クラスがあり、その派生クラスでのみ使用できるようにする場合に特に役立ちます。

0
Daemin