20

ここに私のコードがあります -

#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()なぜこのエラーが発生するのですか? 誰かがこれを説明してもらえますか。

4

7 に答える 7

35

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

于 2010-09-09T08:25:29.493 に答える
16

$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 のプライベートまたは保護された即時基底クラスへのポインターに変換できるということになります。

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

編集2:

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

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

GCC prog.cpp: 関数 'int main()' 内: prog.cpp:27: エラー: 'ベース' は '派生' のアクセスできないベースです</p>

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

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

于 2010-09-09T08:28:40.100 に答える
8

Chusbad は標準に関する詳細な説明を提供してくれました。

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

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

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

設計の観点からprivateは、通常、継承は必要ありません。Liskov Substitution Principleが適用され、public継承を使用するか、実装の詳細であり、構成を使用します。

于 2010-09-09T09:29:46.757 に答える
6

class derivedから継承されていることはわかっていますclass baseが、main()関数はそれを認識していません。main()関数がそれを認識しない理由は、class derivedPRIVATELY から を継承したためclass baseです。

したがって、 に代入しようとするnew derivedptr、ポインターの型に互換性がありません。

于 2010-09-09T08:27:00.567 に答える
5

これを試して:

#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;
}
于 2010-09-09T08:26:25.927 に答える
1

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

于 2010-09-09T09:44:34.283 に答える
0

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

于 2010-09-09T08:26:16.800 に答える