1

2 つのクラス間のフレンド機能に問題があります。いくつかのコードを見てみましょう:

ファーストクラス:

#ifndef _FIRST_H_
#define _FIRST_H_

//#include "Second.h"
#include <string>

class Second;
class First
{
    friend void Second::fun();

    std::string str = "Dziala\n";
public:
    First();
    ~First();
};
#endif

および 2 番目のクラス:

#ifndef _SECOND_H_
#define _SECOND_H_

#include<iostream>
#include "First.h"

class Second
{
    First fObj;
public:
    Second();
    ~Second();
    void fun() { std::cout << fObj.str; }
};
#endif 

CLASSを友達にしようとしても問題ありません。上記の例のように FUNCTION をフレンドにすると問題が発生します。これは First クラスの #include "Second.h" で修正できますが、インクルード ループになります。これを行う方法はありますか?

4

3 に答える 3

2

上記の例のように FUNCTION をフレンドにすると問題が発生します。

// #include "Second.h"
#include <string>

class Second;
class First
{
    friend void Second::fun();
...

最初の行は class の宣言ですSecond前方宣言です。classSecondの場合、その宣言の後、その定義が表示される前は、それは不完全な typeです。SoSecondはクラス型として知られていますが、含まれるメンバーは unknownです。したがって、ここではメンバーを使用できませんvoid Second::fun()

friend class Second不完全な型のメンバーを使用しようとしないため、正常に動作します。

しかし、それはインクルードループになります。

MadsMarquart が言ったように、既にヘッダー ガードがあるので問題ありません。

これを行う方法はありますか?

フレンド宣言として使用する場合はfriend void Second::fun()、宣言と定義の順序が重要であり、クラスを少し変更する必要があります。

  1. クラスを宣言しますFirst
  2. の宣言(定義ではない)でクラスSecondを定義します。 fun()
    • が定義されておらず、のコンストラクターが現在不明であるため、 First fObjas メンバーを使用したりnew First、現在試みたりすることはできません。ポインターまたは参照で問題ありません。FirstFirst
    • ポインタまたは参照を使用するため、**コンストラクタも変更する必要があります。
  3. Firstのフレンド宣言でクラスを定義しfun()ます。
  4. を定義しfun()ます。

あなたの例に基づいて修正されたコード、

class First;

class Second {
 public:
  Second(First& rfObj) : fObj(rfObj) {}
  void fun();

 private:
  First& fObj;
};

class First {
  friend void Second::fun();
 public:
  First() = default;

private:
  std::string str = "Dziala\n";
};

void Second::fun() { std::cout << fObj.str; }
于 2016-02-08T09:36:50.183 に答える
0

完全なクラス定義が表示されない限り、メンバー関数をフレンドとして宣言することはできません。そうしないと、クラスの作成者が意図していないクラスのメンバーを任意のコードで宣言および定義できるようになります。

class Second     // complete class definition, not just a forward declaration
{
    public:

       void fun();
};

class First
{
    friend void Second::fun();
};

この結果、 はFirst単に のメンバーになることはできませんSecond。それを受け入れるには、コンパイラは の定義をコンパイルするために の完全な定義を可視化する必要がありますがSecondFirstコンパイルする の定義のために の完全な定義を可視化する必要もありFirstますSecond。これは無限に再帰的な依存関係であり、コンパイラを混乱させる傾向があります。

前方宣言のみで宣言できるクラスメンバー (または実際には一般的な変数) の唯一の型は、ポインターまたは参照です。

だから、これはうまくいくでしょう

class First;

class Second     // complete class definition, not just a forward declaration
{
    private:
        First &fObj;    // note this is a reference
    public:

       void fun();

       Second();
       ~Second();
};

class First
{
    friend void Second::fun();
};

Second::Second() : fObj(*(new First))   // assumes First has appropriate (not shown) constructor
{}

Second::~Second()
{
   delete &fObj;
}

ただし、の定義が事前にコンパイラに表示されてSecondいない限り、 のコンストラクタとデストラクタの両方をコンパイルできないことに注意してください。Firstこれは、前方宣言のみに基づいてクラス型のインスタンスを作成または破棄できないためです (つまり、元の問題と同じ理由)。

Second実際には、クラスをフレンドとして宣言して、それでFirst完了です。結局のところ、クラスの 1 つのメンバー関数をフレンドとして宣言すると、メンバー関数が常に意図したとおりに機能するように実装されることが保証されます。クラスの単一のメンバー関数が必要に応じて機能することを信頼できるが、同じクラスの他のメンバー関数を信頼できないという状況はほとんどありません。

于 2016-02-08T10:22:11.300 に答える
0

これを行う方法はありますか?

friendメカニズムを使用して、しようとしていることを行うことはできません。

簡単な解決策は、メンバー関数を介して公開First::strし、構造を気にしないことfriendです。それはロングショットによるよりクリーンなソリューションです。

class First
{
  public:
    First();
    ~First();

    std::string const& getString() const { return str; }

  private:
    std::string str = "Dziala\n";
};
于 2015-11-06T22:06:42.293 に答える