ヒューマントーク
ここで何が起こっているかを説明することから始めましょう。すでに知っている場合はご容赦ください。ただし、フォローアップに必要なコンテキストが作成されます。
コンパイラは、修飾Aされていないものをに解決し::C::Aます (ソース レベルで自分で変更を加えた場合、結果は同じになります)。にアクセスできないため::C::A、エラー メッセージが出力されます。
::C::Aアクセスできないことをコンパイラが検出し、への参照をフォールバックとしてAへの参照と見なす必要があることを提案しています。::Aただし、::C::Aと::Aは簡単に 2 つのまったく異なるものになる可能性があります。
ここで何をすべきかを自動的に推測することは、バグや髪を引っ張る¹またはその両方を導入する傾向があるだけでなく、C++ の精神に完全に反します。
標準語
この動作が C++11 標準に直接準拠し、設計どおりであることを確認します。
§9/2 は次のように述べています。
クラス名は、クラス名が表示された直後に宣言されているスコープに挿入されます。class-nameは、クラス自体のスコープにも挿入されます。これは、
注入されたクラス名として知られています。
これは、 class のスコープ内にC、A注入されたクラス名があることを意味します。
§3.4/3 は、注入されたクラス名が名前検索の候補であると述べています。
クラスの注入されたクラス名も、名前の隠蔽と検索のために、そのクラスのメンバーと見なされます。
§3.4/1 は、ベースにアクセスできAないことが、注入されたクラス名の A考慮を妨げないことを明確にしています。
アクセス ルールは、名前の検索と関数のオーバーロードの解決 (該当する場合) が成功した場合にのみ考慮されます。
§11.1/5 は、議論中の正確な状況を直接説明しています。
[注: 派生クラスでは、基本クラス名のルックアップは、それが宣言されたスコープ内の基本クラスの名前ではなく、注入されたクラス名を見つけます。注入されたクラス名は、それが宣言されたスコープ内の基本クラスの名前よりもアクセスしにくい場合があります。—終わりのメモ]
標準では、次の例も提供されています。これは、あなたのものと同等です。
class A { };
class B : private A { };
class C : public B {
A *p; // error: injected-class-name A is inaccessible
::A *q; // OK
};
A¹が最初はpublicベースで、後でprivateリファクタリング中になるとどうなるか想像してみてください。::Aまた、と::C::Aは無関係であることを想像してください。(以前は機能していた)のような呼び出しはアクセスできなくなっa->foo()たため失敗すると予想されますが、代わりに の型が背後で変更され、「メソッドがありません」というエラーが発生します。は?!?もちろん、それは起こりうる最悪の事態とはほど遠いものです。fooafoo