6

このコードについて次の 2 つの質問があります。

namespace A { class window; }

void f(A::window);

namespace A
{
    class window
    {
    private:
       int a;
       friend void ::f(window);
    };
}

void f(A::window rhs)
{
    std::cout << rhs.a << std::endl;
}

1) ::f(window) を実行して、ウィンドウ クラス内のメンバー関数 f をグローバルに修飾する必要があるのはなぜですか?

2) この特定のケースで関数 f(A::window) を事前に宣言する必要があるのはなぜですか。一方、クラスが名前空間内で定義されていない場合、関数がフレンドとして宣言された後に関数を宣言しても問題ありません。

4

3 に答える 3

4

フレンドとして宣言するとき、前方宣言がまだ存在しない場合、f()実際にはそれを含むクラス (この場合) の外側の名前空間で行われます。A

したがって、この...

namespace A
{
    class window
    {
    private:
        friend void ::f(window);
    };
}

本質的にこれになります...

namespace A
{
    class window;
    void f(window);

    class window
    {
    private:
        friend void f(window);
    };
}

編集:これは、このシナリオについて明示的に説明している C++ 標準のスニペットです。

標準 7.3.1.2 / 3 :

名前空間で最初に宣言されたすべての名前は、その名前空間のメンバーです。非ローカル クラスのフレンド宣言が最初にクラスまたは関数を宣言する場合、そのフレンド クラスまたは関数は、最も内側のエンクロージング名前空間のメンバーです。フレンドの名前は、非修飾ルックアップ (3.4.1) または修飾ルックアップ (3.4.3) によって、その名前空間スコープで一致する宣言が提供されるまで (クラス定義がフレンドシップを付与する前または後に) 検出されません。

于 2012-06-07T17:57:02.783 に答える
3

1) に関しては、関数は名前空間にないため、 :: を使用してコンパイラに名前空間の外で検索するように指示する必要があります。

それ以外の場合は、名前空間内の関数のみを検索します (それが存在する理由です)。ウィンドウ クラスは名前空間内にあるため、Koenig ルックアップはここでは適用されません。

2)についてはよくわかりませんが、1)に関連していると思います。

于 2012-06-07T17:57:47.783 に答える
1

1) 関数fが現在の名前空間の外で宣言および定義されているため。クラスの定義を関数と同じ名前空間に移動した場合、グローバルかどうかに関係なく、その必要はありません。

2) 参照される前に常に関数を宣言する必要があります。あなたのクラスは、friend ステートメントで関数を参照します。

于 2012-06-07T17:58:22.327 に答える