4

ええ、質問のトピックは何度も議論されてきました。そして、私はその違いについてほとんど明確です。この本の例に関連して、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ヘッダー ファイルをインクルードする必要があります。前方宣言はここでは機能しません (間違っていたら訂正してください)。clearScreenIndex

さて、次に進みます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

私の前の質問にリンクされている質問は、それをよく説明しています。ただ、上記の状況ではうまくいかないので、再度質問させていただきます。

4

2 に答える 2

1

クラスを使用していない限り、つまり、オブジェクトのメソッドを呼び出したり、インスタンスの new を呼び出したり、クラスのインスタンスの配列を予約したりしない限り、前方宣言のみを使用できます。つまらないルールとして、前方宣言を使用してもコンパイラが文句を言わない場合は、前方宣言を使用し、コンパイルを遅くするインクルードを避けてください。

唯一の危険: 多重継承を使用してキャストし、インクルードがない場合、キャストはうまく機能しませんが、これは通常、使用するクラスを含める必要がある .cpp で行います。

于 2013-05-14T19:43:32.037 に答える