web-dev-qa-db-ja.com

別のクラスで使用するクラスのメンバー関数を前方宣言するにはどうすればよいですか?

相互にポインタを使用して、2つの同一のクラスXとYを作成しました。 X.hについては、以下のコードを参照してください。Y.hは、すべてのXとYが交換されたものと同じです。ただし、このコードでは、メソッドConnectでエラーが発生します(エラーC2027:未定義のタイプ 'Y'の使用)。 X.hで、クラスYを前方宣言しましたが、YにSetXPointerという名前のメソッドがあることを知りません。したがって、このメソッドも前方宣言する必要がありますよね?

これを実行しようとすると(行クラスY;の下に行Y :: SetXPointer(X * pX_in);を追加すると、コンパイラエラーC2761が発生します: 'void Y :: SetXPointer(X *)':メンバー関数の再宣言禁止されている。クラスXでクラスYのパブリックメソッドを使用する方法はありますか?

// X.h

#pragma once

#include "Y.h"

// Forward declaration
class Y;

class X
{
public:
    X(void) : data(24) {};
    ~X(void) {};
    int GetData() { return data; }
    void SetYPointer(Y* pY_in) { pY = pY_in; }
    Y* GetYPointer() { return pY; }
    void Connect(Y* Y_in) { pY = Y_in; Y_in->SetXPointer(this); }
private:
    int data;
    Y *pY;
};
12

クラス本体にメソッド本体を含めないでください。両方のクラスを記述し、両方のクラスが完了したら、メソッドの実装を記述します。

class Y;
class X {
  …
  void Connect(Y* Y_in);
  …
};
class Y {
  …
  void Connect(X* X_in);
  …
};
inline void X::Connect(Y* Y_in) {
  pY = Y_in;
  Y_in->SetXPointer(this);
}
inline void Y::Connect(X* X_in) {
  pX = X_in;
  X_in->SetXPointer(this);
}

そうすれば、クラスのオブジェクトがメモリにどのように配置されるかについての完全な情報が、Connectメソッドが実装されるまでに利用可能になります。また、クラス本体のメソッドとinlineで宣言されたメソッドはどちらも同じようにインライン化されるため、パフォーマンスも同じになります。

唯一の欠点は、これら2つのクラスを2つのヘッダーに適切な方法で分割できないことです。

14
MvG

これを行う唯一の方法は、両方のクラスのメソッドに完全な型が必要な場合、実装を実装ファイルに分離することです。

3
Luchian Grigore

XとYの間で実装の大部分を共有する場合は、テンプレートを使用して共有することをお勧めします。一例は次のとおりです。

template<bool isX> class XY
{
public:
  typedef XY<!isX> YX; // This is the opposite type to the current one.
  XY(void) : data(24) {};
  ~XY(void) {};
  int GetData() { return data; }
  void SetPointer(YX* pYX_in) { pYX = pYX_in; }
  YX* GetPointer() { return pYX; }
  void Connect(YX* YX_in) { pYX = YX_in; YX_in->SetPointer(this); }
private:
  int data;
  YX *pYX;
};

typedef XY<true> X;
typedef XY<false> Y;

テンプレートメソッドは使用時にのみインスタンス化されるため、インスタンス化されるまでに両方のタイプがわかっているため、上記の問題を回避できます。後でXYの間に違いがある場合は、typedefの代わりに継承を使用できます。

2
MvG

クラスBをクラスAに配置できます

using namespace std;

class A
{
        public:
        void run()
        {
                B b("hi");
                b.run(this);
        }

        void print(string &msg) { cout << msg << endl; }

        private:
        class B
        {
                public:
                B(string m) : msg(m) {}
                void run(A *a) { a->print(msg); }

                private:
                string msg;
        };
};

int main()
{
        A a;
        a.run();
        return 0;
}
1
edW