11

次のようなクラスがあります。

class ClassA
{
  public:
    float Get(int num) const;
  protected:
    float& Get(int num);
}

クラスの外では、Get() 関数を呼び出します。

float foo = classAInstance.Get(i);

これで公開バージョンが呼び出されることを期待していますが、代わりに Visual Studio でエラーが発生します。

error C2248: 'ClassA::Get' : cannot access protected member declared in class 'ClassA'

保護されたオーバーロードをコメント アウトし、それへのすべての参照を削除すると、コードがコンパイルされます。

アクセス可能なメンバーが利用可能な場合、コンパイラがアクセスできないメンバーを使用しようとするのはなぜですか? コンパイラに正しいオーバーロードを強制的に選択させる方法はありますか? メンバー関数の解決規則への参照はどこにありますか?

4

2 に答える 2

9

確かに、オーバーロードの解決はアクセシビリティ チェックの前に行われます。標準のセクション 13.3 ( [over.match]) は次のように述べています。

オーバーロードの解決は、呼び出しの引数となる式のリストと、呼び出しのコンテキストに基づいて呼び出すことができる候補関数のセットが与えられた場合に、呼び出すのに最適な関数を選択するためのメカニズムです。最適な関数の選択基準は、引数の数、引数が候補関数のパラメーターの型リストとどの程度一致するか、(非静的メンバー関数の場合) オブジェクトが暗黙的なオブジェクト パラメーターとどの程度一致するか、およびその他の特定のものです。候補関数のプロパティ。[注: オーバーロードの解決によって選択された関数は、コンテキストに適しているとは限りません。関数のアクセシビリティなどのその他の制限により、呼び出しコンテキストでの使用が不適切になる可能性があります。— エンドノート]

通常の修正は、公開関数と保護関数に別の名前を付けることです。


これは時々役立つことに注意してください。例:

class Blah
{
    const std::string& name_ref;

    Blah(const char*) = delete;

public:
    Blah(const std::string& name) : name_ref(name) {}

    void do_something_with_name_ref() const;
};

std::string s = "Blam";
Blah b(s); // ok

name_refからのみ読み取られることに注意してくださいconst。ただし、const参照は一時オブジェクトにバインドできます。一時オブジェクトにバインドするname_refと、ダングリング参照になり、 で未定義の動作が発生しdo_something_with_name_ref()ます。

Blah c("Kablooey!"); // would be undefined behavior
                     // the constructor overload makes this a compile error

プライベート コンストラクターのオーバーロードは、一時的なstd::stringコンストラクターが暗黙的に構築およびバインドされるのを防ぎます。

于 2011-06-04T21:58:21.670 に答える
5

オーバーロードの解決が最初に行われ、後でアクセス チェックが行われます。

const と非 const の両方のオーバーロードがある場合、これは、関数が呼び出されるオブジェクトの constness によって解決されます。

于 2011-06-04T21:58:33.827 に答える