2

これが私のコードと要件です:

私は2つのクラスAとBを持っていますが、それらには継承がありません。クラスAの1つのメソッドを使用して、クラスBの1つのメソッドを呼び出しました。次に、クラスBのメソッドは、クラスAのメソッドの1つをコールバックして、コールバックを実行する必要があります。

コードの一部:

classA.h:

#include "classB.h"

class classA
{
  public:
  classA();
  classB *pClassB;
  void callClassB();
  void callBack();
};

classA.cpp:

#include "classA.h"
classA::classA()
{
  pClassB = new classB();
}

void classA::callBack()
{
  return;
}

void classA::callClassB()
{
  pClassB->callFunction();
}

classB.h:

class classB
{
  public:
  classB();
  void callFunction();
}

classB.cpp:

#include "classB.h"
classB::classB()
{
}

void classB::callFunction()
{
   // I should call classA's callback here!
}

問題は、classA.hをclassB.hに含めることができないことです。これは、他の場所でコンパイルの問題が発生するためです(それを解決することはできません)。classBをclassAのサブクラスとして作成することはできません(可能であれば、classA::callBack()代わりに作成する必要があります)。では、この状況に対する解決策はありますか?

更新:それは私が変更したものです:

class classB
{
  public:
  classB(classA& pCallBack);
  void callFunction();
  void (classA::*m_callback)(void);
};

classA::classA()
{
  pClassB = new classB(*this);
}

classB::classB(classA& pCallBack)
{
  m_callback = pCallBack;
}

ポインタを保存しようとしましたが、失敗しました。「互換性のないタイプからの割り当て」と表示されます...何が問題になっていますか?

4

3 に答える 3

7

実際、両方のヘッダーを相互に含めることは循環依存関係であり、コンパイラーはこれを解決できません。これを解決するにはさまざまな方法がありますが、そのうちの3つを以下に説明します。

前方宣言の使用

循環依存関係を解消する最も簡単な方法は、前方宣言を使用することです。前方宣言は、指定された名前がクラスを示すことのみをコンパイラーに通知します。その型へのポインタ/参照のみを使用する場合はこれで十分です。これらの場合、コンパイラはその型の完全な定義を必要としないためです。したがって、次のようにclassA.hを変更できます。

class classB;

class classA
{
  public:
  classA();
  classB *pClassB;
  void callClassB();
  void callBack();
};

このようにして、ヘッダーはclassB.hに依存しなくなります。もちろん、classA.cpp#includeのそのヘッダーに移動する必要があります。

#include "classA.h"
#include "classB.h"
...

インターフェースの紹介

もう1つの方法は、にスーパーインターフェイス(またはC ++では抽象スーパークラス)を導入し、classAそれclassBだけを表示することです。

callback.h:

class callback
{
  public:
  virtual void callBack() = 0;
};

classA.h:

#include "callback.h"

class classB;

class classA : public callback
{
  public:
  classA();
  classB *pClassB;
  void callClassB();
  void callBack();
};

classB.h:

#include "callback.h"

class classB
{
  callback& m_a;
public:
  classB(callback& a);
  void callFunction();
};

classB.cpp:

#include "classB.h"

classB::classB(callback& a) : m_a(a) {}

classB::callFunction()
{
  m_a.callBack();
}

ご覧のとおり、この方法classBはまったく依存していませんclassA。これにより、実際には、の定義に触れることなく、後でclassA他の実装に置き換えることができます。callbackclassB

関数ポインタの紹介

さらに別の可能性は、のそれに一致する関数ポインタ型を定義/使用し、オブジェクト全体ではなくclassA::callBack()、コールバック関数へのポインタのみをに渡すことです。ただし、これはメソッドとシームレスにのみ機能します。非静的関数の場合は、呼び出し用のオブジェクトが必要です。classBclassAstaticclassA

アップデート

変更したコードでは、2つのアプローチ(オブジェクトをclassA渡すか、関数ポインターのみを渡す)を組み合わせています。一度に1つずつ固執する方がよいでしょう。最初のアプローチはより単純です、これはそれがどのように見えるかです:

class classA;

class classB
{
  classA& m_a;
public:
  classB(classA& a);
  void callFunction();
};

classB::classB(classA& a) : m_a(a) {}

classB::callFunction()
{
  m_a.callBack();
}

関数ポインターとそれを呼び出すオブジェクトの両方が必要だったため、非静的メンバー関数の場合、関数ポインターのアプローチはより複雑になります。@Tadeuszの回答には、別の見方が示されています。

于 2012-04-20T10:13:28.000 に答える
3

コールバックだけが必要な場合は、クラスBがクラスAについて何も知る必要はありません。コールバックを渡すだけです。ブースト(C ++ 11より前)のソリューションを提供します:

classB.h:

#include <boost/function.hpp>

class classB
{
    void callFunction(boost::function<void()> callback);
}

classB.cpp

void classB::callFunction(boost::function<void()> callback)
{
    callback();
}

classA.cpp:

#include <boost/bind.hpp>

void classA::callBack()
{
  return;
}

void classA::callClassB()
{
  pClassB->callFunction(boost::bind(&classA::callBack, this));
}
于 2012-04-20T10:29:03.390 に答える
2

前方宣言を使用します。例:

classA.h:

class classB; // forward declaration
class classA
{
  public:
  classA();
  classB *pClassB;
  void callClassB();
  void callBack();
};

classB.h:

class classA; // forward declaration
class classB
{
  public:
  classB();
  void callFunction(classA& a);
  // could store pointer to classA instance here instead
}

これは、classA.hのclassBへの参照またはポインターのみを使用している限り機能します。その逆も同様です。

classA.cpp:

#include "classA.h"
#include "classB.h"
classA::classA()
{
  pClassB = new classB(); // could pass 'this' to classB here instead
}

void classA::callBack()
{
  return;
}

void classA::callClassB()
{
  pClassB->callFunction(*this);
}

classB.cpp:

#include "classB.h"
#include "classA.h"
classB::classB()
{
}

void classB::callFunction(classA& a)
{
   a.callback();
}
于 2012-04-20T10:14:55.550 に答える