c関数ポインタの定義とC++コールバック関数の使用

6839 ワード

*************************************************************************************************************************************************************************************************
     typedef
  C++        (   typedef     ) 
( )          。
//  1:    (*   )(   ) 
char (*pFun)(int); 
char glFun(int a){ return;} 
void main()
{ 
pFun = glFun; 
(*pFun)(2); 
} 
            pFun。
           “  1”                ,         int ,    char  。                ,            。
          glFun()。         int     char   。
              ——               ,                   。
       main()   ,            ——    glFun        pFun。main()       “*pFun”    pFun        ,          glFun()   ,       2
 )  typedef      。
//  2:typedef     (*   )(   )
typedef char (*PTRFUN)(int); 
PTRFUN pFun; 
char glFun(int a){ return;} 
void main() 
{ 
pFun = glFun; 
(*pFun)(2); //   pFun(2);
}
typedef          。          PTRFUN   ,                 ,       int      char  。        int,char    PTRFUN 。
                   pFun,          1         。
( ) C++        。 
//  3:typedef     (  ::*   )(   ) 
class CA
{
public: 
char lcFun(int a)
 { 
  return;
 }
 }; 
CA ca;
typedef char (CA::*PTRFUN)(int); 
PTRFUN pFun; 
void main() 
{ 
pFun = CA::lcFun; 
ca.(*pFun)(2);
} 
   ,            “   ” “  ”,                            new   。
CA *pca = new CA; 
pca->(*pFun)(2); 
delete pca; 
                   ,       this  。
  : CA       PTRFUN m_pfun; 
void CA::lcFun2() 
{ 
(this->*m_pFun)(2);
}
   ,            “->*” “.*”   。 

*************************************************************************************************************************************************************************************************
関数ポインタは通常、コールバックを実現するために使用されます.基本的な使い方は次のとおりです.
1、関数ポインタタイプの定義
//int Fun(int a)のプロトタイプを定義します.の関数ポインタ
typedef int (*PTRFUN) ( int aPara );
2、関数ポインタ変数の定義
PTRFUN pFun;//pFunは関数ポインタ変数名
int (*pFun2) ( int a );//pFun 2も関数ポインタ変数名
3、関数ポインタを関数のパラメータとして渡す
//コールバック関数の定義
int CallBack( int a ){
    return++a;
}
//コールバック関数の定義
void Caller(PTRFUN cb)/void Caller(int(*cb)(int)//このように明記することもできますが、値を伝える際には関数ポインタ(すなわち関数名でパラメータを持たない)だけが必要です
{
    int nPara = 1;
    int nRet = cb( nPara );
}
//コールバックの使用
void Test(){
    Caller( CallBack );//コールバック関数の直接使用
    PTRFUN cb = CallBack;//int (*cb) ( int ); cb = CallBack;
    int nRet1 = cb( 99 );//nRet1 = 100;
}
4、関数ポインタのポインタ使用
//関数ポインタを定義するポインタ
typedef int (**PTRPTRFUN) ( int aPara );
//関数ポインタのポインタをパラメータとして
void PtrCaller(PTRPTRFUNcb)//void PtrCaller(PTRFUN*cb)//ポインタの説明
//void PtrCaller(int(**cb)//プロトタイプ説明
{
    int nRet = (*cb)(999);//nRet = 1000;
}
//関数ポインタを使ったポインタ
void Test(){
    PTRFUN cb = CallBack;
    PtrCaller( &cb );
}
5、関数ポインタ配列の使用
//関数ポインタ配列の定義
PTRFUN fArray[10];       //int (*fArray[10]) ( int );//プロトタイプ定義
for ( int i = 0; i < 10; i++ ){
    fArray[i] = CallBack;
    int nRet = fArray[i](i);   //nRet = i+1;
}
6、関数ポインタの大きさ
//ポインタと呼ぶ以上、普通のポインタと同じ32ビットシステムでも大きさは4
int nSz1 = sizeof(PTRFUN);     //nSz1 = 4;
int nSz2 = sizeof(PTRPTRFUN);  //nSz2 = 4;
注意:
コンパイラには、Visual C++など、さまざまな呼び出し仕様があります.cdecl,_stdcallまたは_pascalは、呼び出し仕様(デフォルトは_cdecl)を表します.
呼び出し仕様は、コンパイラによって生成される所定の関数名、パラメータ伝達の順序(右から左または左から右)、スタッククリーンアップ責任(呼び出し者または呼び出し者)、およびパラメータ伝達メカニズム(スタック、CPUレジスタなど)に影響します.
********************************************************************************************************************************************************************************************************
C++コールバック関数の使用
すばらしい比喩は:コールバック関数はあなたが持っているBP機のようです:他の人にあなたの番号を教えて、彼が仕事がある时callあなた!
代表的な言語(C、Object Pascal)とアーキテクチャ(CORBA)を比較して、コールバックの実現方法、具体的な役割などを分析します.
プロセス言語におけるコールバック(C)(1)関数ポインタコールバックは,C言語において関数ポインタによって実現され,コールバック関数のアドレスを被調関数に渡すことによってコールバックが実現される.したがって、コールバックを実現するには、まず関数ポインタを定義する必要があります.次の例を参照してください.
       void Func(char *s);//関数プロトタイプvoid(*pFunc);//関数ポインタ
関数の定義は、関数ポインタの定義と非常に似ていることがわかります.
一般化では,関数ポインタタイプの変数定義を簡略化し,プログラムの可読性を高めるために,関数ポインタタイプをカスタマイズする必要がある.
       typedef void(*pcb)(char *);
コールバック関数は、通常の関数のようにプログラムによって呼び出されてもよいが、それがパラメータとしてコールバック関数に渡される場合にのみコールバック関数と呼ばれる.
変調関数の例:
void GetCallBack(pcb callback){}ユーザは、上記の関数を呼び出す際に、pcbタイプのコールバック関数を自分で実現する必要がある:void fCallback(char*s){}そして、fCallbackを直接変数としてGetCallBack,GetCallBack(fCallback)に渡すことができます.
パラメータに異なる値が割り当てられている場合、呼び出し元は異なるアドレスの関数を呼び出します.割り当ては、実行時に発生し、動的バインドを実現します.
(2)パラメータ伝達規則はこれまで,ANSI C/C++のコンパイラ仕様に注意せずに関数ポインタおよびコールバックのみを議論してきた.多くのコンパイラにはいくつかの呼び出し仕様があります.Visual C++の場合、関数タイプの前に_を付けることができます.cdecl,_stdcallまたは_pascalは、その呼び出し仕様(デフォルトは_cdecl)を表す.C++Builderは、_fastcall呼び出し仕様もサポートする.呼び出し仕様は、コンパイラによって生成される所定の関数名、パラメータ伝達の順序(右から左または左から右)、スタッククリーンアップ責任(呼び出し者または呼び出し者)、およびパラメータ伝達メカニズム(スタック、CPUレジスタなど)に影響する.
呼び出し仕様を関数タイプの一部と見なすことが重要である.互換性のない呼び出し仕様で関数ポインタにアドレスを割り当てることはできません.例:
//呼び出された関数はintをパラメータ、intを戻り値_stdcall int callee(int);
//呼び出し関数関数関数ポインタをパラメータvoid caller(_cdecl int(*ptr)(int))とする.
//pに呼び出された関数アドレスを格納しようとする不正な動作_cdecl int(*p)(int) = callee;//エラー
ポインタpとcallee()のタイプは、異なる呼び出し仕様があるため互換性がありません.したがって、ポインタpには、同じ戻り値とパラメータ列があるにもかかわらず、呼び出し元のアドレスを割り当てることはできない.