現代C++のコールバック技術--std::bindとstd::functionを使用する

11286 ワード

最近、陳碩大牛の「Linuxマルチスレッドサービス側プログラミング」とmuduoソースコードを読んだ後、その中のいくつかの実現の詳細に対して非常に深い印象を持っていて、特にstd::bindとstd::functionのコールバック技術を使用しています.この二つの大殺器はまるで現代C++の「任督二脈」であり、継承時の虚関数の指代不明の問題さえ解決できると言える.ここではstd::bindとstd::functionを用いたC++オブジェクト間の使い方を詳細に述べ,イベント駆動を解決するプログラミングモデルに合わせる.筆者は勉強が浅いので、説明が正しくなければ、友达に教えてもらいたいと思っています.
以下のすべての議論はオブジェクトに基づいている.
bindとfunctionの基礎的な使い方

#include
#include
typedef std::function<void()> Functor;
class Blas
{
    public:
        void add(int a,int b)
        {
            std::cout << a+b << std::endl;
        }

        static void addStatic(int a,int b)
        {
            std::cout << a+b << std::endl;
        }
};

int main(int argc,char** argv)
{
    Blas blas;

//  bind         
    Functor functor(std::bind(&Blas::addStatic,1,2));

//  bind    chengyuan  
    Functor functor(std::bind(&Blas::add,blas,1,2));

    functor();
    return 0;
}

上記のコードの違いは、クラスの静的メンバー関数でない場合、パラメータバインド時にバインドされたパラメータリストに使用するオブジェクトを追加する必要があることです.
functionとbindを使用してコールバック機能を実現
#include
#include

typedef std::function<void()> Functor;

class Blas
{
    public:
        void setCallBack(const Functor& cb)
        {functor = cb;};

        void printFunctor()
        {functor();};
    private:
        Functor functor;
};

class Atlas
{
    public:
        Atlas(int x_) : x(x_)
        {
            //            

           blas.setCallBack(std::bind(&addStatic,x,2));
        //              
                  blas.setCallBack(std::bind(&Atlas::add,this,x,2));
        }

        void print()
        {
            blas.printFunctor();
        }
    private:
        void add(int a,int b)
        {
            std::cout << a+b << std::endl;
        }

        static void addStatic(int a,int b)
        {
            std::cout << a+b << std::endl;
        }

        Blas blas;
        int x;
};

int main(int argc,char** argv)
{
    Atlas atlas(5);
    atlas.print();
    return 0;
}

上記のコードの
void add();
void addStatic();

2つの関数はAtlasクラスにあり、Atlasのデータメンバーを自由に操作できます.add()系列の関数を関数オブジェクトとしてカプセル化してBlasに転送し,Blasクラスで呼び出すが,それらは依然としてAtlasデータメンバーを操作する機能を有し,両クラス間で弱い結合作用を形成している.しかし、2つのクラス間で弱い結合を形成するには、std::bind()パッケージを使用するときにthisポインタを入力する必要があります.
std::bind(&Atlas::add,this,1,2);

すなわち,2つのクラス間で結合を形成するには,非静的メンバー関数(プライベートでも共有でもよい)を用いる.コードは次のとおりです.
#include
#include

typedef std::function<void()> Functor;

class Blas
{
    public:
        void setCallBack(const Functor& cb)
        {functor = cb;};

        void printFunctor()
        {functor();};
    private:
        Functor functor;
};

class Atlas
{
    public:
        Atlas(int x_,int y_) : x(x_),y(y_)
        {
            //             
                        blas.setCallBack(std::bind(&Atlas::add,this,x,2));
        }
        void print()
        {
            blas.printFunctor();
        }

    private:
        void add(int a,int b)
        {
            std::cout << y << std::endl;
            std::cout << a+b << std::endl;
        }
        Blas blas;
        int x,y;
};

int main(int argc,char** argv)
{
    Atlas atlas(5,10);
    atlas.print();
    return 0;
}

これにより、AtlasはBlasクラスにいくつかの関数オブジェクトを登録することができ、これらの関数オブジェクトはBlasデータを処理すると同時に(std::bindに位置を残してBlasに伝わるパラメータ)、またAtlasのデータを処理し、コールバック作用を形成することができる.コードは次のとおりです.
#include
#include

typedef std::function<void(int,int)> Functor;

class Blas
{
    public:
        void setCallBack(const Functor& cb)
        {functor = cb;};

        void printFunctor()
        {functor(x,y);};

    private:
        int x = 10;
        int y = 10;
        Functor functor;
};

class Atlas
{
    public:
        Atlas(int x_,int y_) : x(x_),y(y_)
        {
            //              
                       blas.setCallBack(std::bind(&Atlas::add,this,std::placeholders::_1,std::placeholders::_2));
        }

        void print()
        {
            blas.printFunctor();
        }

        void printFunctor()
        {functor(x,y);};

    private:
        int x = 10;
        int y = 1:;
        Functor functor;
};

class Atlas
{
    public:
        Atlas(int x_,int y_) : x(x_),y(y_)
        {
           //             
               blas.setCallBack(std::bind(&Atlas::add,this,std::placeholders::_1,std::placeholders::_2));
        }

        void print()
        {
            blas.printFunctor();
        }

    private:
        void add(int a,int b)
        {
            std::cout << y << std::endl;
            std::cout << a+b << std::endl;
        }

        Blas blas;
        int x,y;
};

int main(int argc,char** argv)
{
    Atlas atlas(5,10);
    atlas.print();
    return 0;
}