コールバック関数――C++が互いにヘッダファイルを含む問題を解決する方法


最近2つの通信プロトコルプログラムが書かれており、いずれも電力システムにおける問答式伝送規則であり、1つはTCP伝送ファイルに基づく102規則サービスエンドプログラムであり、1つはシリアルポート収集データに基づく102規則クライアントプログラムである.以前は別の通信規約がありましたが、最近はこれらの通信プロトコルプログラムの共通の部分を抽象化して、新しいプロトコルが来るときに、仕事量を少なくすることができることを期待しています.大体、私はこれらの通信プログラムを以下のように分類します.
1、通信プロトコル類、主に一定の伝送プロトコルに従ってメッセージを組み立てることを担当し、メッセージを分解し、範囲はすべての役割のメッセージ(メインステーション、サブステーション)2、通信制御類を含み、各種の通信制御のサブクラス:TCP、シリアルポートなどを含み、主に通信の確立、通信の閉鎖、メッセージの送信、メッセージの受信3、サービス側の論理類を担当する.主にサービス側に立つロール処理ロジックであり、1、2の2種類のメンバー変数4、クライアントロジッククラスを有し、主にクライアントに立つロール処理ロジックであり、1、2の2種類のメンバー変数を有する.
5、インタフェースクラス、ユーザー、論理クラスとの対話を担当する
とても美しく闻こえて、论理类をやり遂げる时もまだ顺调で、インタフェース类と论理类のインタラクションをする时葛藤しました~私は强迫症があって、もし构造があまりにも赘沢で心が诘まって~前に别の协议を书く时、接触したばかりで业务をよく知らないため、时間がきついので、我慢して论理类とインタフェース类を揉んで、今回は何を言っても彼らを分けます!残念なことに、インタフェースクラスは容易にログをインタフェースに出力することができるが、直接メッセージを送信して受信することはできないが、論理クラスは正反対で、メッセージを制御しているが、メッセージをインタフェースに出力するには足が短い.私はこの2つのクラスが互いにヘッダファイルを含むことを望んでいません.のよし、強迫症は==|.
師匠の指摘を経て,私はコールバック関数でこの問題を解決した.大体以下の通りです.
まず、インタフェースクラスに静的コールバック関数を追加します.
static void CALLBACK PrintLogCallback(void* pInstance, const char* str_log, int len);

決して最初のパラメータを軽視しないでください.彼はインタフェース類の非静的兵力の制勝法宝を動かすことができます.この関数を実装するときは、次のように書くことができます.
void CCOM102Dlg::PrintLogCallback(void* pInstance, const char* str_log, int len)
{
    CCOM102Dlg* pCOM102Dlg = (CCOM102Dlg*) pInstance;
    //    pCOM102Dlg     ,        
    //                      :
    //pCOM102Dlg->AppendLog(str_log, len);
}

これにより、第1のステップが完了します.第2のステップは、論理クラスにコールバック関数を呼び出すインタフェースを追加することです.次のようにします.
typedef void (CALLBACK *PrintLogCallback)(void* pInstance, const char* str_log, int len); 
//               ,      
void SetInterfaceEngine(void *pInstance, PrintLogCallback printLog);

//               
struct InterfaceEngine
{
    void *pInstance;
    PrintLogCallback printLog;
};
InterfaceEngine m_engine;

//          
void PrintLog(const char* buf, int len);

そして、インタフェースクラスの印刷ログ機能が必要な場合は、保存した関数ポインタを探して仕事をすればいいです.
void CClassLogic::SetInterfaceEngine(void *pInstance, PrintLogCallback printLog)
{
    m_engine.pInstance= pInstance;
    m_engine.printLog = printLog;
}

 
void CClassLogic::PrintLog(const char* buf, int len)
{
    if (m_engine.pInstance!= NULL)
    {
        m_engine.printLog(m_engine.pInstance, buf, len);
    }
}

 
だから今はインタフェースクラスに論理クラスのヘッダファイルを含めるだけでいい~CClassLogicのメンバー変数m_を宣言するcLogic、コールバック関数を設定するインタフェースを呼び出すと効果が得られます.
    m_cLogic.SetInterfaceEngine(this, COM102Dlg::PrintLogCallback);