0

特定のクラスから関数の呼び出し元を強制しようとしています。たとえば、次のコードは私の問題を示しています。「use」関数がクラス A からのみ呼び出されるようにしたい。プロジェクト全体でグローバル名前空間を使用しています。

ああ

#include "b.h"
namespace GLOBAL{

class A{
public:
    void doSomething(B);
}
}

a.cpp

#include "a.h"
using namespace GLOBAL;

void A::doSomething(B b){

    b.use();
}

bh

namespace GLOBAL{

class B{
public:
    friend void GLOBAL::A::doSomething(B);
private:
    void use();
}

コンパイラは次のように述べています。

‘GLOBAL::A’ has not been declared

‘void GLOBAL::B::use()’ is private

誰でもここで助けることができますか?

どうもありがとう、

マイク。

4

3 に答える 3

2

これは、フレンド宣言でクラスのメンバーを参照しているためです。

これが機能するためには、コンパイラは A の完全な定義を既に認識している必要があります。

ああ

// #include "b.h"   // remove this line it is not needed.
namespace GLOBAL{

class B; // Forward declare the class here.

class A{
public:
    void doSomething(B&); // Note: This should probably be a reference.
                          // Change to doSomething(B&); 
}
}

bh

// Add this line it is needed for the friend declaration.
// To have a member as a friend we need the definition of 'A'
#include "a.h"

namespace GLOBAL{

class B{
public:
    friend void GLOBAL::A::doSomething(B&);
private:
    void use();
}

a.cpp

#include "a.h"
// Add this line to include the B definition so you know how to call use()
#include "b.h"
using namespace GLOBAL;

void A::doSomething(B& b){ // b should be a reference otherwise you are copying it.

    b.use();
}
于 2012-10-01T18:01:22.160 に答える
1

以下は、cpp ファイルから正常にコンパイルされます。

namespace GLOBAL
{
    class B;

    class A
    {
    public:
        void doSomething(B& b);
    };
};


namespace GLOBAL
{
    class B
    {
    public:
        friend void GLOBAL::A::doSomething(B&);
    private:
        void use()
        {
        }
    };
};

void GLOBAL::A::doSomething(B& b)
{
    b.use();
}

あなたの問題は、Aクラスが定義される前にBクラスを定義する「ah」から「bh」を含めても、BクラスがAクラスへの参照を作成するという事実から生じることがわかります。だからあなたは問題を抱えています。ただし、スタックを介してコピーしているため、タイプ B のオブジェクトを前方宣言することはできません。したがって、なぜクラス B への参照を使用するのですか (これは、B オブジェクトを事前に知る必要がないためです)。

基本的に、解決が必要な構造にいくつかの根本的な問題があります。前方宣言循環依存関係について読む必要があります

編集:クラスAが(Bを参照するAの特定の関数ではなく)Bのフレンドであることを純粋に指定することは、フレンド定義が一種の前方宣言を提供するため、実際には可能です。そのため、次のコードがコンパイルされます。

namespace GLOBAL
{
    class B
    {
    public:
        friend class A;
    private:
        void use()
        {
        }
    };
};

namespace GLOBAL
{
    class A
    {
    public:
        void doSomething(B b);
    };
};

void GLOBAL::A::doSomething(B b)
{
    b.use();
}

あなたのコードのように、最初に投稿された、友人の声明を変更するだけで、

friend class A;

コードをコンパイルできるようにする必要があります。

于 2012-10-01T18:14:29.240 に答える
0

最初のディレクティブの後に移動#include "b.h"します。宣言が適用される関数をコンパイルするまで、コンパイラはフレンド宣言を確認する必要はありません。a.ha.cpp#include

于 2012-10-01T17:59:55.023 に答える