ええ、質問のトピックは何度も議論されてきました。そして、私はその違いについてほとんど明確です。この本の例に関連して、1つだけ疑問があります。
この質問は、C++ Primer という本で例として取り上げた 2 つのクラスを提示した前の質問に関連しています。
これらのクラスを参照して、この本は次の段落を引用しています。特に、WindowManager
クラスのメンバー関数をフレンド関数として宣言することに関連しています。これがそれが言うことです:
メンバー関数を友達にするには、プログラムを注意深く構造化して、宣言と定義の間の相互依存性に対応する必要があります。この例では、プログラムを次のように順序付ける必要があります。
- まず、クリアを宣言するが定義できない Window_mgr クラスを定義します。clear が Screen のメンバーを使用できるようにするには、Screen を宣言する必要があります。
- 次に、clear のフレンド宣言を含むクラス Screen を定義します。
- 最後に、clear を定義します。これにより、Screen のメンバーを参照できるようになりました。
その質問で提示したコードは、この構造のみに従います。しかし、それはうまくいかないようです。これは、上記の点が見当違いであるか、正しく実装していないかを考えさせます。
問題は、関数をクラスでclear
フレンド関数として宣言すると、ヘッダー ファイルが循環的にインクルードされることです。ここでも、両方のクラスの特定の部分を簡単に説明します。ScreenCls
ScreenCls.h:
#ifndef SCREENCLS_H
#define SCREENCLS_H
#include <iostream>
#include "WindowManager.h"
using namespace std;
class ScreenCls {
friend void WindowManager::clear(ScreenIndex);
// Some other code
}
関数はそこで定義されたものを使用しているため、ここではWindowManager.h
ヘッダー ファイルをインクルードする必要があります。前方宣言はここでは機能しません (間違っていたら訂正してください)。clear
ScreenIndex
さて、次に進みますWindowManager.h
:
#ifndef WINDOWMANAGER_H
#define WINDOWMANAGER_H
#include <iostream>
#include <vector>
#include "ScreenCls.h"
using namespace std;
class WindowManager {
public:
// location ID for each screen on window
using ScreenIndex = vector<ScreenCls>::size_type;
private:
vector<ScreenCls> screens{ ScreenCls(24, 80, ' ') };
};
そして、screens
ここの宣言に集中してください。リスト初期化子を使用して、デフォルトScreenCls
をに追加しましたvector
。したがって、ここでも を含める必要がありますWindowManager.h
。そして今、私たちは循環的な包摂に取り組んでいます。これにより、プロジェクトがビルドできなくなります。
ただし、フレンド関数の宣言を変更して、クラス全体をフレンドにするようにすると、そのクラスを操作できforward declaring
ますWindowManager
。その場合はうまくいきます。
つまり、ここでは基本的にフレンド関数は機能していませんが、フレンド クラスは機能しています。では、上記の点が実装でうまくいっていないのでしょうか、それとも私のクラスに何か問題があるのでしょうか? header inclusion
との概念を明確に理解するために、これを知りたいだけですforward declaration
。
私の前の質問にリンクされている質問は、それをよく説明しています。ただ、上記の状況ではうまくいかないので、再度質問させていただきます。