1. ホーム
  2. c++

[解決済み] 継承:'A'は'B'のアクセス不能なベースである

2023-05-12 06:14:54

疑問点

$ cat inheritance.cpp 
#include <iostream>

using namespace std;

class A { };
class B : private A { };

int main() {
    A* ab = new B;
}
$
$ g++ inheritance.cpp
inheritance.cpp: In function 'int main()':
inheritance.cpp:9: error: 'A' is an inaccessible base of 'B'
$

私はちょうどこのエラーが理解できません。

私が理解しているように、そして このチュートリアル が確認します。 private のメンバがどのように変化するかを変更するだけです。 class B のメンバが外界からどのように見えるかを変更するだけです。

private指定は、単に class B のメンバの可視性を変更するだけではないと思います。

  • 継承の際にこのエラーが発生する理由とその意味を教えてください。
  • 基本的に、C++ でこのタイプのコードを許可することの何が問題なのでしょうか? まったく無害に見えますが。

どのように解決するのですか?

継承を非公開にするということは、基本的にBがAを(全く)継承していないという事実さえも非公開である、つまり外部からはアクセスできない/見えないということを意味します。

もしそれが許されるならどうなるかという長ったらしい議論は抜きにして、単純な事実として、それは許されません。派生型のオブジェクトを参照するためにベースへのポインターを使用したい場合は、パブリック継承を使用することにほぼ基づいています。

私的継承は ではない に従うことを必ずしも(あるいは通常も)意図していません。 リスコフ置換の原則 . 公的な継承では、派生オブジェクトは基底クラスのオブジェクトに置き換えられると主張し、適切なセマンティクスは となります。私的継承は ではなく はそう主張しませんが。私的継承が意味する関係の通常の記述は、"is implemented in terms of"です。

public継承は、派生クラスがベースクラスのすべての機能を維持し、さらに追加する可能性があることを意味します。私的継承は、派生クラスがより制限されたインターフェイスを持つものを実装するために一般的なベースクラスを使用するという、多かれ少なかれ反対の意味を持ちます。

例えば、C++標準ライブラリのコンテナがテンプレートではなく継承を使って実装されていると仮定します。現在のシステムで std::dequestd::vector はコンテナであり std::stack はコンテナ・アダプタで、より限定されたインターフェイスを提供します。テンプレートをベースにしているので std::stack のどちらかのアダプタとして使用できます。 std::deque または std::vector .

もし、本質的に同じものを継承して提供したいのであれば、おそらく私的継承を使うでしょうから std::stack のようなものになるでしょう。

class stack : private vector {
    // ...
};

この場合、間違いなく ではなく を操作できるようにしたい。 stack をあたかも vector . そうすると、スタックの期待に反する可能性があります (そしておそらくそうなるでしょう) (たとえば、ユーザーは意図したとおりに純粋にスタックのような方法ではなく、途中でアイテムを挿入したり削除したりできます)。私たちは基本的に vector をスタックを実装するための便利な方法として使用していますが、もし (たとえば) stack をスタンドアローン (基底クラスへの依存なし) で実装するか、あるいは std::deque で再実装することもできます。 ではなく クライアントコードにとって、これは単なるスタックであり、特別な種類の vector (または deque) ではないはずです。