web-dev-qa-db-ja.com

派生*からベース*への変換がプライベート継承で失敗するのはなぜですか?

これが私のコードです-

_#include<iostream>
using namespace std;

class base
{
public:
    void sid()
    {
    }  
};

class derived : private base
{
public:
    void sid()
    {
    }
};

int main()
{
    base * ptr;
    ptr = new derived; // error: 'base' is an inaccessible base of 'derived'
    ptr->sid();
    return 0;
}
_

これにより、コンパイル時エラーが発生します。

_error: 'base' is an inaccessible base of 'derived'
_

コンパイラは基本クラスsid()を呼び出そうとするので、なぜこのエラーが発生するのですか?誰かがこれを説明できますか?.

20
Bruce

$ 11.2/4州-

Nの基本クラスBは、次の場合、Rでアクセスできます。

  • bの発明されたパブリックメンバーは、Nのパブリックメンバー、または
  • RはクラスNのメンバーまたは友人で発生し、Bの発明されたパブリックメンバーはNのプライベートメンバーまたは保護されたメンバー、または
  • Rは、Nから派生したクラスPのメンバーまたは友人で発生し、Bの発明されたパブリックメンバーは、Pのプライベートメンバーまたは保護されたメンバー、または
  • bがRでアクセス可能なSの基本クラスであり、SがRでアクセス可能なNの基本クラスであるようなクラスSが存在します。」

ここで、「B」は「ベース」、「N」は「派生」、「R」はメインです。

  1. 2番目の箇条書きを考えてみましょう-「RはクラスNのメンバーまたは友人で発生します...」。 'R'(メイン)は 'N'(派生)のメンバーでもフレンドでもないため、この句は適用されません。

  2. 3番目の箇条書きを考えてみましょう-「RはクラスPのメンバーまたは友人で発生します...」。この条項は、上記と同じ理由で適用されません。

  3. 4番目の箇条書きを検討してください-もう一度、この条項は適用されません

したがって、「Base」は「Derived」のアクセス可能なクラスではないと結論付けることができます。

$ 11.2/5州-

基本クラスにアクセスできる場合は、派生クラスへのポインターをその基本クラスへのポインターに暗黙的に変換できます(4.10、4.11)。 [注:クラスXのメンバーおよびフレンドは、X *をXのプライベートまたは保護された即時基本クラスへのポインターに暗黙的に変換できることになります。—end note]

Baseでアクセスした場合はDerivedmainのアクセス可能なクラスではないため、派生クラスから基本クラスへの標準変換は不適切です。したがって、エラー。

編集2:

いくつかの一般的なコンパイラのエラーメッセージを調べてください。これは、理解を深めるのに役立ちます。 「アクセスできない」という単語が、すべてのエラーメッセージで頻繁かつ一貫してポップアップすることに注意してください。

参照はドラフト標準N3000からのものです。私はまだ最新のドラフトをダウンロードしていません:)

GCC prog.cpp:関数「intmain()」内:prog.cpp:27:エラー:「base」は「派生」のア​​クセスできないベースです

Comeau Online "ComeauTest.c"、26行目:エラー:アクセスできない基本クラス "base"への変換は許可されていませんptr = new派生;

VS2010エラーC2243:「型キャスト」:「派生*」から「ベース*」への変換は存在しますが、アクセスできません

16
Chubsdad

問題は、継承がプライベートであるため、派生ポインターをベースポインターに変換できないことだと思います。

35
Douglas Leeder

Chusbadは、標準に関する詳細な説明を提供しました。アクセシブルな説明を提供しようと思います。

C++には、publicprotected、およびprivateの3つのアクセスレベル指定子があります。これらは、WHOがメソッド、属性、または基本クラスにアクセスできるかどうかを判断するためのものです。これは、オブジェクト指向言語では一般的です。

ここでは、private継承を選択しました。概念的には、これはDerivedBaseから部外者に継承するという事実を隠そうとすることを意味します。これは通常、これが実装の詳細であることを意味します。

結果として、「外部」はこの関係に気づいていません。これは、コンパイラによってこのinaccessibleメッセージで強制されます。

設計の観点から、private継承は通常必要ありません。リスコフの置換原則が適用され、public継承を使用するか、実装の詳細であり、合成を使用するかのいずれかです。

8
Matthieu M.

_class derived_は_class base_を継承しますが、main()関数はそれを認識していません。 main()関数がそれを認識しない理由は、_class derived_が_class base_からPRIVATELYを継承するようにしたためです。

したがって、_new derived_をptrに割り当てようとすると、ポインタタイプに互換性がありません。

6

これを試して:

#include<iostream>
#include<conio.h>
using namespace std;

class base
{
      private:
      public:
          virtual void sid() // You might want to declare sid virtual
             {
                  cout<<"base";
             } 
          virtual ~base() // You then probably need a virtual destructor as well.
             {
             } 
};

class derived : public base //public inheritance
{
      private:
      public:
             void sid()
             {
                  cout<<"derived";
             }
};

int main()
{
    base * ptr;
    ptr = new derived;
    ptr->sid();
    getch();
    return 0;
}
5
ereOn

これによりエラーC2243が発生します: '型キャスト': '派生*'から 'ベース*'への変換は存在しますが、アクセスできませんこの派生クラスはプライベートに継承されているため、派生取得の作成時に基本クラスオブジェクトは作成されません。派生オブジェクトを作成するには、最初に呼び出して、発生しない基本クラスオブジェクトを作成します。解決策は、クラスを公に導出することです。メンバー関数で仮想キーワードを使用するかどうかは関係ありません。

1
Santosh kumar

基本クラスのsid()関数を仮想として宣言する必要があります。仮想関数は、派生クラスに置き換えることができます。そうしないと、コンパイラエラーが発生する可能性があります。

0