プライベート継承では、derived* からbase* への変換が失敗するのはなぜですか?
-
01-10-2019 - |
質問
これが私のコードです -
#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()
なぜこのエラーが発生するのでしょうか?誰かこれを説明してください。
解決
$11.2/4州-
N の基本クラス B は、次の場合に R でアクセスできます。
- B の作成されたパブリック メンバーは N のパブリック メンバーになる、または
- R は、クラス N のメンバーまたはフレンド、および発明されたパブリックで発生します B のメンバーは、プライベートまたは protected メンバー N の場合、または
- R は N から派生したクラス P のメンバーまたはフレンドに出現し、 Bの発明されたパブリックメンバーは、 P の private メンバーまたは protected メンバー、または
- B が R でアクセス可能な S の基底クラスであるようなクラス S が存在する S は N の基底クラスでアクセス可能です。 Rで」
ここで、「B」は「Base」、「N」は「Derived」、「R」はメインです。
2 番目の箇条書き「R はクラス N のメンバーまたは友人に発生します...」について考えてみましょう。「R」(メイン) は「N」(派生) のメンバーでもフレンドでもないため、この条項は適用されません。
3 番目の箇条書き「R は、クラス P のメンバーまたは友人に発生します...」について考えてみましょう。この条項も上記と同じ理由で適用されません。
4 番目の箇条書きを検討してください。この条項も適用されません。
したがって、「Base」は「Derived」のアクセス可能なクラスではないと結論付けることができます。
$11.2/5 州 -
基底クラスが アクセス可能であれば、暗黙的に 派生クラスへのポインタ その基底クラスへのポインタ(4.10、 4.11).[ 注記:したがって、クラス X のメンバーと友人は、 X* をポインターに暗黙的に変換する プライベートまたは保護された即時に X の基底クラス。—終了注記]
以来 Base
はアクセス可能なクラスではありません Derived
でアクセスしたとき main
, 、派生クラスから基本クラスへの標準変換は不正な形式です。したがって、エラーが発生します。
編集2:
いくつかの一般的なコンパイラのエラー メッセージを研究すると、理解を深めるのに役立ちます。すべてのエラー メッセージにわたって、「アクセス不能」という単語が頻繁かつ一貫してポップアップ表示されることに注目してください。
参考文献はドラフト規格 N3000 からのものです。私はまだ最新のドラフトをダウンロードしていません:)
GCC prog.cpp:関数 'int main()'です。プログ.cpp:27:エラー:'base' は 'derived' のアクセスできない基底
Comeau Online「ComeauTest.c」、26 行目:エラー:アクセスできないベースへの変換 クラス "base" は 許可 ptr = 新しい派生;
VS2010 エラー C2243:'タイプキャスト' :'derived *' から 'base への変換 *' は存在するが、アクセスできない
他のヒント
問題は、継承がプライベートであるため、派生ポインターをベースポインターに変換できないことだと思います。
Chusbadは、標準を含む詳細な説明を提供しました。アクセス可能な説明を提供しようとします。
C ++では、3つのアクセスレベルの仕様があります。 public
, protected
と private
. 。これらは、誰がメソッド、属性、または基本クラスにアクセスできるかを判断することを目的としています。オブジェクト指向の言語の中で典型的です。
ここで、あなたは選出しました private
継承。概念的には、これはあなたがその事実を隠そうとすることを意味します Derived
継承します Base
部外者にとって、これは一般に、これが実装の詳細であることを意味します。
結果として、「外観」はこの関係に気付いていません。これは、これによりコンパイラによって実施されます inaccessible
メッセージ。
デザインの観点から、 private
継承は一般に必要ありません。リスコフ代替原則が適用され、使用します public
継承、それは実装の詳細であり、構成を使用します。
あなたはそれを知っています class derived
継承します class base
, 、 しかし main()
機能はそれを知りません。理由 main()
機能はあなたが作ったことを知りません class derived
個人的に継承します class base
.
したがって、割り当てようとするとき new derived
に ptr
, 、ポインタータイプは互換性がありません。
これを試して:
#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;
}
これにより、エラーC2243:「タイプキャスト」:「派生 *」から「ベース *」への変換が存在しますが、この導出されたクラスは個人的に継承されていません。派生オブジェクトを作成するには、最初の呼び出しが発生していないベースクラスオブジェクトを作成します。 Soltuionは、クラスを公開することです。メンバー関数を使用して仮想キーワードを使用するかどうかは重要です。
ベースクラスでsid()関数を仮想として宣言する必要があります。仮想関数は、派生クラスに置き換えることができます。それ以外の場合は、コンパイラエラーが発生する可能性があります。