1. 程式人生 > >muduo庫中的核心:std::bind和std::function

muduo庫中的核心:std::bind和std::function

muduo main ons 源碼 綁定 func 靜態成員 con 函數

最近在讀完陳碩大牛的《Linux多線程服務端編程》以及muduo源碼後,對其中的一些實現細節有著十分深刻的印象,尤其是使用std::bind和std::function的回調技術。可以說,這兩個大殺器簡直就是現代C++的“任督二脈”,甚至可以解決繼承時的虛函數指代不清的問題。在此詳細敘述使用std::bind和std::function在C++對象之間的用法,用以配合解決事件驅動的編程模型。筆者才疏學淺,如果解釋的不正確希望朋友們不吝賜教。
下面的所有討論基於對象。

std::bind和std::function的基礎用法

#include<iostream>
#include<functional>

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;
}

上述代碼中的區別是:如果不是類的靜態成員函數,需要在參數綁定時,往綁定的參數列表中加入使用的對象。

使用std::function和std::bind實現回調功能

#include<iostream>
#include<functional>

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();

兩個函數在Atlas類中,並且可以自由操作Atlas的數據成員。盡管是將add()系列的函數封裝成函數對象傳入Blas中,並且在Blas類中調用,但是它們仍然具有操作Atlas數據成員的功能,在兩個類之間形成了弱的耦合作用。但是如果要在兩個類之間形成弱的耦合作用,必須在使用std::bind()封裝時,向其中傳入this指針:

std::bind(&Atlas::add,this,1,2);

也就是說,要在兩個類之間形成耦合作用,要使用非靜態的成員函數(私有和公有都可以)。代碼如下:

#include<iostream>
#include<functional>

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<iostream>
#include<functional>

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;
}

muduo庫中的核心:std::bind和std::function