程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> boost function對象

boost function對象

編輯:C++入門知識

本文根據boost的教程整理。

主要介紹boost function對象的用法。

boost function
boost function是什麼
boost function是一組類和模板組合,用於包裝各種函數。從功能上,它類似於函數指針,但是比函數指針的功能更強大。

 


使用boost function,必須包含頭文件


[cpp]  #include <boost/function.hpp> 

#include <boost/function.hpp>
除了頭文件外,不需要額外的庫。

注意,boost function有兩種形式:一種為推薦形式;另外一種為可移植形式。推薦形式的語法更加簡潔;可移植形式的可移植性好,但是語法羅嗦。由於目前的gcc/vc的版本都已經能夠使用推薦形式了,因此,可移植形式就不在描述。有興趣的可以參閱boost相關文檔。

boost function 基本用法
例如,有一個函數


[cpp]  float int_div(int x, int y) 

    return ((float)x)/y; 

float int_div(int x, int y)
{
    return ((float)x)/y;
}

我們可以這樣使用


[cpp]  oost::function<float (int x, int y)> f; 
f = int_div; 
std::cout<< f(5,3) << std::endl; 

    boost::function<float (int x, int y)> f;
    f = int_div;
    std::cout<< f(5,3) << std::endl;

可以看到,它的用法和函數指針很相似的。

當然,boost::function不止這些,請看下面的函數對象:


[cpp]  struct int_add { 
    float operator()(int x, int y) { 
        return (float)(x + y); 
    } 
}; 

struct int_add {
    float operator()(int x, int y) {
        return (float)(x + y);
    }
};

上面的 boost::function<float (int x, int y)> f 聲明的f對象,仍舊可以保存int_add:


[cpp]  f = int_add(); 
std::cout << "f add : "<< f(10,20) << std::endl; 

    f = int_add();
    std::cout << "f add : "<< f(10,20) << std::endl;

 

另外,boost::function還可以用來判斷函數是否為空


[cpp]  f(f) 
    std::cout  << " f is ok!"<< std::endl; 

    if(f)
        std::cout  << " f is ok!"<< std::endl;

要清空f,可以使用


[cpp]  f = 0; 
if(!f) 
    std::cout << "f is cleard!" << std::endl; 

    f = 0;
    if(!f)
        std::cout << "f is cleard!" << std::endl;

 

針對成員函數
成員函數,也可以被綁定,如有類
[cpp]  struct X { 
    int foo(int x) { 
        std::cout << "X " << this << " foo x="<<x << std::endl; 
        return x + 100; 
    }; 
}; 

struct X {
    int foo(int x) {
        std::cout << "X " << this << " foo x="<<x << std::endl;
        return x + 100;
    };
};

可以這樣使用
[cpp] boost::function<int (X*, int)> mf; 
mf = &X::foo; 
 
X x; 
mf(&x, 5); 

    boost::function<int (X*, int)> mf;
    mf = &X::foo;

    X x;
    mf(&x, 5);


和bind同時使用
在需要包裝參數的場合,我們可以配合boost::bind一起使用。
首先,加入boost::bind的頭文件
[cpp] #include <boost/bind.hpp> 

#include <boost/bind.hpp>
這樣使用
[cpp]  boost::function<int (int)> mbf; 
mbf = bind(&X::foo, &x, _1); 
mbf(10); 

    boost::function<int (int)> mbf;
    mbf = bind(&X::foo, &x, _1);
    mbf(10);

bind將x的指針保存在function對象中。

 


function factory
function factory是一個封裝類工廠的模板。它有兩種,一種是value_factory,一種是factory。


[cpp]
boost::factory<T*>()(arg1,arg2,arg3)  
// same as new T(arg1,arg2,arg3)  
 
boost::value_factory<T>()(arg1,arg2,arg3) 
// same as T(arg1,arg2,arg3) 

boost::factory<T*>()(arg1,arg2,arg3)
// same as new T(arg1,arg2,arg3)

boost::value_factory<T>()(arg1,arg2,arg3)
// same as T(arg1,arg2,arg3)

使用function factory的原因
我們考慮這樣的場景:使用抽象工廠模式,有一個接口,有若干個實現,通常的做法是這樣的:
[cpp]
//聲明接口  
class Interface  

public: 
   virtual void print(int a) = 0; //接口函數  
}; 
//聲明抽象工廠  
class Interface_Factory { 
public: 
    virtual Interface * create() = 0; 
}; 

//聲明接口
class Interface
{
public:
   virtual void print(int a) = 0; //接口函數
};
//聲明抽象工廠
class Interface_Factory {
public:
    virtual Interface * create() = 0;
};
然後,我們有若干個實現
[cpp]
class ImplA : public Interface 

public: 
   virtual void print(int a) { 
      std::cout << "== A ==  a=" << a << std::endl; 
   } 
}; 
//提供ImplA的類工廠  
class ImplA_Factory : public Interface_Factory 

public: 
    Interface * create() { return new ImplA(); } 
    static ImplA_Factory _implAFactory; 
}; 
ImplA_Factory ImplA_Factory::_implAFactory; 
 
//同理,ImplB的實現  
 
class ImplB : public Interface 

public: 
   virtual void print(int a) { 
      std::cout << "== B ==  a=" << a << std::endl; 
   } 
}; 
//提供ImplB的類工廠  
class ImplB_Factory : public Interface_Factory 

public: 
    Interface * create() { return new ImplB(); } 
    static ImplB_Factory _implBFactory; 
}; 
ImplB_Factory ImplB_Factory::_implBFactory; 

class ImplA : public Interface
{
public:
   virtual void print(int a) {
      std::cout << "== A ==  a=" << a << std::endl;
   }
};
//提供ImplA的類工廠
class ImplA_Factory : public Interface_Factory
{
public:
    Interface * create() { return new ImplA(); }
    static ImplA_Factory _implAFactory;
};
ImplA_Factory ImplA_Factory::_implAFactory;

//同理,ImplB的實現

class ImplB : public Interface
{
public:
   virtual void print(int a) {
      std::cout << "== B ==  a=" << a << std::endl;
   }
};
//提供ImplB的類工廠
class ImplB_Factory : public Interface_Factory
{
public:
    Interface * create() { return new ImplB(); }
    static ImplB_Factory _implBFactory;
};
ImplB_Factory ImplB_Factory::_implBFactory;
如果你要使用它,就需要這些寫
[cpp]
std::map<std::string, Interface_Factory*> factories; 
 
int main() 

    factories["A"] = &ImplA_Factory::_implAFactory; 
    factories["B"] = &ImplB_Factory::_implBFactory; 
..... 

std::map<std::string, Interface_Factory*> factories;

int main()
{
    factories["A"] = &ImplA_Factory::_implAFactory;
    factories["B"] = &ImplB_Factory::_implBFactory;
.....
}
如果仔細觀察下,就會發現,實際上,ImplA_Factory和ImplB_Factory的內容幾乎都一樣。但是卻寫了不少重復性的代碼。factory就是解決該問題的。


factory的解決之道
使用boost::factory,是完全不需要定義Interface_Factory接口和對應的實現的,我們定義一個boost::function對象,替代Interface_Factory
[cpp]

typedef boost::function< I *() > I_factory; //替代Interface_Factory的定義 

typedef boost::function< I *() > I_factory; //替代Interface_Factory的定義用boost::factory替代ImplA_Factory和ImplB_Factory:
[cpp]
std::map<std::string, I_factory> factories; 
.... 
 
    factories["A"] = boost::factory<ImplA*> ();  //等價於 &ImplA_Factory::_ImplAFactory;  
    factories["B"] = boost::factory<ImplB*> (); //等價於 &ImplB_Factory::_ImplBFactory; 

std::map<std::string, I_factory> factories;
....

    factories["A"] = boost::factory<ImplA*> ();  //等價於 &ImplA_Factory::_ImplAFactory;
    factories["B"] = boost::factory<ImplB*> (); //等價於 &ImplB_Factory::_ImplBFactory;

在使用的時候,與普通方法絲毫不差,如
[cpp]
void run_interface(const char* name) 

    I_factory factory = factories[name]; 
    if(!factory) 
    {    
        std::cout<<"factory " << name << " is not exist" << std::endl; 
        return; 
    }    
    I *i = factory(); 
    i->print(100); 
    delete i; 

void run_interface(const char* name)
{
    I_factory factory = factories[name];
    if(!factory)
    {  
        std::cout<<"factory " << name << " is not exist" << std::endl;
        return;
    }  
    I *i = factory();
    i->print(100);
    delete i;
}
通過判斷factory的函數是否為空,就可以知道對應的類實現是否存在。我們可以這樣簡單的使用
[cpp]
run_interface("A"); 
run_interface("B"); 
run_interface("C"); 

    run_interface("A");
    run_interface("B");
    run_interface("C");由於"C"對象不存在,因此,將打印 "factory C is not exist"的信息。


OverloadedFunction
考慮下面的代碼
[cpp]
const std::string& identity_s(const std::string& x) // Function (as pointer).  
    { return x; } 
 
int identity_i_impl(int x) { return x; } 
int (&identity_i)(int) = identity_i_impl; // Function reference.  
 
double identity_d_impl(double x) { return x; } 
boost::function<double (double)> identity_d = identity_d_impl; // Functor. 

const std::string& identity_s(const std::string& x) // Function (as pointer).
    { return x; }

int identity_i_impl(int x) { return x; }
int (&identity_i)(int) = identity_i_impl; // Function reference.

double identity_d_impl(double x) { return x; }
boost::function<double (double)> identity_d = identity_d_impl; // Functor.
在調用他們的時候,必須使用各自的函數名:identity_i, indentity_s, indentity_d; 例如
[cpp]
BOOST_TEST(identity_s("abc") == "abc"); 
BOOST_TEST(identity_i(123) == 123); 
BOOST_TEST(identity_d(1.23) == 1.23); 

BOOST_TEST(identity_s("abc") == "abc");
BOOST_TEST(identity_i(123) == 123);
BOOST_TEST(identity_d(1.23) == 1.23);
但是,使用OverlaodedFunction,就可以使用統一的名字identity來調用了:
[cpp]
boost::overloaded_function< 
      const std::string& (const std::string&) 
    , int (int) 
    , double (double) 
> identity(identity_s, identity_i, identity_d); 
 
// All calls via single `identity` function.  
BOOST_TEST(identity("abc") == "abc"); 
BOOST_TEST(identity(123) == 123); 
BOOST_TEST(identity(1.23) == 1.23); 

boost::overloaded_function<
      const std::string& (const std::string&)
    , int (int)
    , double (double)
> identity(identity_s, identity_i, identity_d);

// All calls via single `identity` function.
BOOST_TEST(identity("abc") == "abc");
BOOST_TEST(identity(123) == 123);
BOOST_TEST(identity(1.23) == 1.23);

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved