封装
最近在看陈硕的MUDUO网络通信库的过程中,发现作者大量使用了Boost::function以及Boost::bind功能,为了能够正常的学习作者的代码,决定先弄明白function以及bind的功能。
Boost::Function 是对函数指针的对象化封装,在概念上与广义上的回调函数类似。相对于函数指针,function除了使用自由函数,还可以使用函数对象,甚至是类的成员函数,这个就很强大了哈。
1. 一个简单的示例代码
01 | #include <boost/function.hpp> |
02 | #include <boost/bind.hpp> |
03 | #include <iostream> |
04 | |
05 | using namespace std; |
06 | |
07 | |
08 | class TestA |
09 | { |
10 | public : |
11 | void method() |
12 | { |
13 | cout<< "TestA: method: no arguments" <<endl; |
14 | } |
15 | |
16 | void method( int a, int b) |
17 | { |
18 | cout<< "TestA: method: with arguments" |
19 | << "value of a is:" <<a |
20 | << "value of b is " <<b <<endl; |
21 | } |
22 | }; |
23 | |
24 | |
25 | void sum( int a, int b) |
26 | { |
27 | int sum = a + b; |
28 | cout<< "sum: " <<sum<<endl; |
29 | } |
30 | |
31 | int main() |
32 | { |
33 | boost::function< void ()> f; |
34 | TestA test; |
35 | |
36 | f = boost::bind(&TestA::method, &test); |
37 | f(); |
38 | |
39 | f = boost::bind(&TestA::method, &test, 1, 2); |
40 | f(); |
41 | |
42 | f = boost::bind(&sum, 1, 2); |
43 | f(); |
44 | } |
输出结果:
1 | Administrator@8bd5ec9e02074bf ~/source |
2 | $ ./BoostFunction.exe |
3 | TestA: method: no arguments |
4 | TestA: method: with argumentsvalue of a is:1value of b is 2 |
5 | sum: 3 |
2. 应用:Thread封装
在实现自定义的线程类时,曾经这么干过:定义虚函数run(),用户自定义的CustomThread::Thread后,自己实现run()函数就OK了。 当时觉得这么做也不错。
现在有了boost::function/boost::bind我们可以这么干:
定义一个线程类:
.h文件
01 | #include <pthread.h> |
02 | #include <string> |
03 | #include <boost/function.hpp> |
04 | #include <boost/bind.hpp> |
05 | |
06 | using namespace std; |
07 | class Thread |
08 | { |
09 | typedef boost::function< void ()> ThreadFun; |
10 | public : |
11 | Thread( const ThreadFun& threadFun, const string& threadName = string()); |
12 | pid_t getThreadId(); |
13 | string getThreadName(); |
14 | int start(); |
15 | |
16 | private : |
17 | static void * startThread( void * thread ); |
18 | |
19 | private : |
20 | pthread_t m_thread; //线程句柄 |
21 | pid_t m_tid; //线程ID |
22 | string m_strThreadName; //线程名称 |
23 | bool m_bStarted; //线程是否启动 |
24 | ThreadFun m_func; //线程处理函数 |
25 | }; |
.cpp文件
01 | #include "thread.h" |
02 | |
03 | Thread::Thread( const Thread::ThreadFun& threadFun, const string& threadName): |
04 | m_func(threadFun), m_strThreadName(threadName) |
05 | { |
06 | } |
07 | |
08 | int Thread::start() |
09 | { |
10 | m_tid = pthread_create(&m_thread, NULL, &startThread, this ); |
11 | return 0; |
12 | } |
13 | |
14 | void * Thread::startThread( void * obj) |
15 | { |
16 | Thread* thread = static_cast <Thread*>(obj); |
17 | thread ->m_func(); |
18 | return NULL; |
19 | } |
20 | |
21 | pid_t Thread::getThreadId() |
22 | { |
23 | return m_tid; |
24 | }; |
25 | |
26 | string Thread::getThreadName() |
27 | { |
28 | return m_strThreadName; |
29 | } |
测试程序
01 | void ThreadProcess() |
02 | { |
03 | int count = 100; |
04 | for ( int i = 0; i < count; i++) |
05 | { |
06 | if (i % 10 == 0) |
07 | cout<< "\n" ; |
08 | cout<<i<< "\t" ; |
09 | } |
10 | } |
11 | |
12 | int main() |
13 | { |
14 | boost::function< void ()> f; |
15 | f = boost::bind(&ThreadProcess); |
16 | Thread thread (f, "ThreadTest" ); |
17 | thread .start(); |
18 | sleep(1000*1000); |
19 | return 0; |
20 | } |
输出结果(Cygwin):

>根据上述程序,我们可以发现,这样我们就不需要定义很多很多的类去继承Thread类,而只需要写好线程运行函数,set到Thread类中即可。不过也不能说利用虚函数留接口给用户实现就不好,只不过现在多了一种方法。(陈硕很反对用虚函数作为结构提供给用户去做实现,但是我现在还没有切身的体会觉得那里不好)
3. 总结
注:
1. 这边只是简单的用boost::function/bind结合pthread简单的实现了一个自己封装的线程类,
自己以前在windows下实现的基于虚函数的线程类实现:http://my.oschina.net/myspaceNUAA/blog/41014
2. boost::function/bind还有很多其他高级用法,我这边只是用来当做一个函数指针用了哈
3. 测试环境:cygwin