zoukankan      html  css  js  c++  java
  • boost--function

    1、简介

      function是一个模板类,它就像一个包装了函数指针的容器(只有一个元素),function对象可以存储函数指针、Lambda表达式、函数对象(比如bind表达式的结果)。function非常适合代替函数指针,存储用于回调的函数,我们完全可以使用function其来代替函数指针。

    如下定义了一个能够容纳void(int)类型的function对象:

    function<void(int)> funo;

      使用function需要包含头文件"boost/function.hpp",C++11已经支持function。

      一些成员函数:

      target():返回对象内部的可调用物Functor的指针,对象为空则返回NULL
      contains():检测是否持有一个Functor。
      clear():将对象清空,与"= 0"效果相同。
      empty():测试对象是否为空,也可以在一个bool上下文中直接测试它是否为空。
      operator==、operator!=:与一个函数或函数对象进行比较。
      operator():调用内部的可调用物,它也会将参数传给可调用物。

    2、简单使用

    int FuncName(int a, int b)
    {
        return a + b;
    }
    
    int main()
    {
        function<int(int, int)> funo;
        funo = FuncName;
        if (funo)
        {
            cout << funo(3, 4) << endl;
        }
    
        return 0;
    }
    View Code

    3、用于回调

      ①、存储普通函数

      以下为在CTestClass类中使用function对象m_fFun来保存回调函数和调用回调函数的示例,CTestClass的成员函数SetCallBack()被定义成了模板函数,这样更方便:

    void call_back_func(int i)
    {
        cout << i << endl;
    }
    
    class CTestClass
    {
    public:
        CTestClass(int i) :m_iNum(i) {}
    public:
        template<typename CallBack>
        void SetCallBack(CallBack f)
        {
            m_fFun = f;
        }
        void run()
        {
            if(m_fFun)
                m_fFun(m_iNum);
        }
    private:
        function<void(int)> m_fFun;
        int m_iNum;
    };
    
    int main()
    {
        CTestClass dc(10);
        dc.SetCallBack(call_back_func);
        dc.run();
    
        return 0;
    }
    View Code

      ②、存储Lambda表达式

    class Bar
    {
    public:
        std::function<void()> onClick;
    };
    
    class Foo
    {
    public:
        Foo()
        {
            b = new Bar;
            //存储Lambda,捕获this指针,使lambda内可调用本类的成员
            b->onClick = [this] {
                func();
            };
        }
        void func()
        {
            cout << "func" << endl;
        }
    private:
        Bar* b;
    };
    
    int main()
    {
        //存储Lambda,捕获变量num
        int num = 100;
        std::function<void()> f = [num] {
            cout << "num:" << num << endl;
        };
        f();
    
        getchar();
        return 0;
    }
    View Code

       ③、存储函数对象

      使用function来存储函数对象是function的重要功能之一,因为相比于使用普通函数回调,使用函数对象回调可以保存数据和实现复杂的操作。以下为在CTestClass类中使用function对象m_fFun来保存回调函数对象和调用回调函数对象的示例

    #include "boost/bind.hpp"
    class CFunObj
    {
    public:
        CFunObj(int i) :x(i) {}
    public:
        void operator()(int i)
        {
            cout << i * x++ << endl;
        }
    private:
        int x;
    };
    
    class CTestClass
    {
    public:
        CTestClass(int i) :m_iNum(i) {}
    public:
        template<typename T>
        void SetCallBack(T f)
        {
            m_fFun = f;
        }
        void run()
        {
            if (m_fFun)
                m_fFun(m_iNum);
        }
    private:
        function<void(int)> m_fFun;
        int m_iNum;
    };
    
    int main()
    {
        CTestClass dc(10);
        CFunObj cfo(2);
        dc.SetCallBack(ref(cfo));
        dc.run();
        dc.run();
    
        return 0;
    }
    View Code

      function使用拷贝语义来保存函数或函数对象,当函数或函数对象很复杂或者禁止拷贝的时候可以使用ref()以解决拷贝的问题。从以上示例代码可以看到,在使用SetCallBack设置回调的时候就是使用ref()来传递的引用包装器,SetCallBack是模板函数,所以T类型在函数调用的时候就是ref()引用包装类型。

      ④、存储类的成员函数

      以下我们定义了一个函数工厂类,回调函数都在这个工厂类中定义,我们可以配合bind来保存类中的回调函数,然后通过fiunction对象再调用类中的回调函数:

    #include "boost/bind.hpp"
    class CCall_back_factory
    {
    public:
        void call_back_fun_1(int i)
        {
            cout << i * 2 << endl;
        }
        void call_bcak_fun_2(int i, int j)
        {
            cout << i * j * 2 << endl;
        }
    };
    
    class CTestClass
    {
    public:
        CTestClass(int i) :m_iNum(i) {}
    public:
        template<typename CallBack>
        void SetCallBack(CallBack f)
        {
            m_fFun = f;
        }
        void run()
        {
            if(m_fFun)
                m_fFun(m_iNum);
        }
    private:
        function<void(int)> m_fFun;
        int m_iNum;
    };
    
    int main()
    {
        CTestClass dc(10);
        CCall_back_factory cbf;
        
        dc.SetCallBack(bind(&CCall_back_factory::call_back_fun_1, cbf, _1));
        dc.run();
    
        int j = 5;
        dc.SetCallBack(bind(&CCall_back_factory::call_bcak_fun_2, cbf, _1, j));
        dc.run();
    
        return 0;
    }
    View Code

     通过以上示例代码可以看到,function用于回调再配合bind解决了类的成员函数不能作为回调函数的问题,而且使用更加灵活。 C++中A类对象里调用B类对象的成员函数一般使用以下三种方法:

      ①、使用虚函数:在A类中保存B类对象的基类指针m_ptr,在B类中重写基类的虚函数,通过B类的基类指针m_ptr来调用B类的虚函数。
      ②、使用function + bind:在A类中保存B类对象的成员函数的function(通过bind),通过function来调用B类的成员函数。
      ③、使用function + lambda:在A类中保存B类对象的成员函数的function(通过捕获this指针的lambda),通过function来调用B类的成员函数。

    4、给线程函数传入多个参数

      我们知道,线程函数只有一个void*参数,利用bind和function可以间接实现给线程函数传入多个参数:

    #include <Windows.h>
    #include "boost/bind.hpp"
    
    void RealFun(char* p, int& n)
    {
        cout << p << n << endl;
        n = 0;
    }
    
    DWORD WINAPI ThreadFunc(void* param)
    {
        function<void()> func = *((function<void()>*)param);
        func();
    
        return 0;
    }
    
    int main()
    {    
        char* p = "value is :";
        int i = 10;
    
        function<void()> func = boost::bind(&RealFun, p, ref(i));
        HANDLE hThread = CreateThread(NULL, 0, ThreadFunc, &func, 0, 0);
        WaitForSingleObject(hThread, INFINITE);
        
        assert(i == 0);
    
        return 0;
    }
    View Code
  • 相关阅读:
    HIVE Group by、join、distinct等实现原理
    【1.3】shell基础——调试shell(sh -x)
    sql server无法显示请求的对话框,检索数据失败
    sql server索引操作
    sql server中的alter
    tempdb无法收缩。使用 DBCC FREESYSTEMCACHE 解决
    在从该备份集进行读取时,RESTORE 检测到在数据库 "CISDB" 中的页(0:0)上存在错误。系统断定检查已失败
    【1.2】shell基础——stty erase解决按backspace出现^H的情况
    【1.1】shell基本实践——密码输入三次错误则结束
    (5.3.7)数据库迁移——sql server备份文件的加密解密
  • 原文地址:https://www.cnblogs.com/milanleon/p/7498849.html
Copyright © 2011-2022 走看看