muduo2 面向对象编程风格 VS 基于对象编程风格(boost::bind/function)

本文主要通过实现Thread 类来展现两种编程风格的不同点。


很多人没有区分“面向对象”和“基于对象”两个不同的概念。面向对象的三大特点(封装,继承,多态)缺一不可。通常“基于对象”是使用对象,但是无法利用现有的对象模板产生新的对象类型,继而产生新的对象,也就是说“基于对象”没有继承的特点。而“多态”表示为父类类型的子类对象实例,没有了继承的概念也就无从谈论“多态”。现在的很多流行技术都是基于对象的,它们使用一些封装好的对象,调用对象的方法,设置对象的属性。但是它们无法让程序员派生新对象类型。他们只能使用现有对象的方法和属性。所以当你判断一个新的技术是否是面向对象的时候,通常可以使用后两个特性来加以判断。“面向对象”和“基于对象”都实现了“封装”的概念,但是面向对象实现了“继承和多态”,而“基于对象”没有实现这些。----摘自网络


一、面向对象编程风格

Thread 类图:

注:下划线表示静态成员

Thread.h:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
#ifndef _THREAD_H_
#define _THREAD_H_

#include <pthread.h>

class Thread
{
public:
    Thread();
     virtual ~Thread();

     void Start();
     void Join();

     void SetAutoDelete( bool autoDelete);

private:
     static  void *ThreadRoutine( void *arg);  //没有隐含的this 指针
     virtual  void Run() =  0;
    pthread_t threadId_;
     bool autoDelete_;
};

#endif  // _THREAD_H_

Thread.cpp:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 
#include  "Thread.h"
#include <iostream>
using  namespace std;


Thread::Thread() : autoDelete_( false)
{
    cout <<  "Thread ..." << endl;
}

Thread::~Thread()
{
    cout <<  "~Thread ..." << endl;
}

void Thread::Start()
{
    pthread_create(&threadId_,  NULL, ThreadRoutine,  this);
}

void Thread::Join()
{
    pthread_join(threadId_,  NULL);
}

void *Thread::ThreadRoutine( void *arg)
{
    Thread *thread =  static_cast<Thread *>(arg);
    thread->Run();  //线程结束,线程对象也得析构
     if (thread->autoDelete_)
         delete thread;
     return  NULL;
}

void Thread::SetAutoDelete( bool autoDelete)
{
    autoDelete_ = autoDelete;
}

Thread_test.cpp:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
#include  "Thread.h"
#include <unistd.h>
#include <iostream>
using  namespace std;

class TestThread :  public Thread
{
public:
    TestThread( int count) : count_(count)
    {
        cout <<  "TestThread ..." << endl;
    }

    ~TestThread()
    {
        cout <<  "~TestThread ..." << endl;
    }

private:
     void Run()
    {
         while (count_--)
        {
            cout <<  "this is a test ..." << endl;
            sleep( 1);
        }
    }

     int count_;
};

int main( void)
{
    TestThread *t2 =  new TestThread( 5);
    t2->SetAutoDelete( true);
    t2->Start();
    t2->Join();

     for (; ; )
        pause();

     return  0;
}

有几个点需要注意:
1、Thread类是虚基类,TestThread类继承来实现虚函数run()。
2、根据 pthread_create 的原型
<strong>int <span class="highlight" style="background-color: rgb(255, 204, 204);">pthread_create</span>(pthread_t *</strong><em>thread</em><strong>, const pthread_attr_t *</strong><em>attr</em><strong>,
                   void *(*</strong><em>start_routine</em><strong>) (void *), void *</strong><em>arg</em><strong>);</strong>

start_routine 参数是一般的函数指针,故不能直接将run() 作为此参数,因为run()是成员函数,隐含this指针,故实现一个静态成员函数ThreadRoutine(), 在里面调用run(),此外参数arg 我们传递this指针,在ThreadRoutine()内将派生类指针转换为基类指针来调用run()。

3、把run()实现为private是为了不让用户直接调用,因为这样根本就没有产生线程调度。
4、注意区分线程与线程对象,设置autoDetele_ 成员也是为了当线程结束时能够立刻销毁线程对象。在main函数内,主线程pthread_join()等待线程结束;run()结束后会delete 掉线程对象,否则要一直等到main函数结束才会被自动销毁。


二、基于对象编程风格

boost bind/function库的出现,替代了stl中的mem_fun,ptr_fun  ,bind1st,bin2nd等函数,这些函数参考 这里
下面举例boost bind/function 的使用。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using  namespace std;
class Foo
{
public:
     void memberFunc( double d,  int i,  int j)
    {
        cout << d << endl; //打印0.5
        cout << i << endl; //打印100
        cout << j << endl; //打印10
    }
};
int main()
{
    Foo foo;
    boost::function< void ( int)> fp = boost::bind(&Foo::memberFunc, &foo,  0. 5, _1,  10);
    fp( 100);
    boost::function< void ( intint)> fp2 = boost::bind(&Foo::memberFunc, &foo,  0. 5, _1, _2);
    fp2( 100200);
    boost::function< void ( intint)> fp3 = boost::bind(&Foo::memberFunc, boost::ref(foo),  0. 5, _1, _2);
    fp3( 5566);
     return  0;
}


boost bind/function 实现转换函数接口。
fp(100); 等价于 (&foo)->memberFunc(0.5, 100, 10); 即_1 是占位符,如果绑定的是一般的函数,则bind 中的参数中不再需要this指针,当然一般函数也没有类名前缀。
boost::ref() 表示引用,fp3(55, 66); 相当于foo.memberFunc(0.5, 55, 66);

Thread 类图:

typedef boost::function<void ()> ThreadFunc;


Thread.h:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
#ifndef _THREAD_H_
#define _THREAD_H_

#include <pthread.h>
#include <boost/function.hpp>

class Thread
{
public:
     typedef boost::function< void ()> ThreadFunc;
     explicit Thread( const ThreadFunc &func);

     void Start();
     void Join();

     void SetAutoDelete( bool autoDelete);

private:
     static  void *ThreadRoutine( void *arg);
     void Run();
    ThreadFunc func_;
    pthread_t threadId_;
     bool autoDelete_;
};

#endif  // _THREAD_H_

Thread.cpp:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 
#include  "Thread.h"
#include <iostream>
using  namespace std;


Thread::Thread( const ThreadFunc &func) : func_(func), autoDelete_( false)
{
}

void Thread::Start()
{
    pthread_create(&threadId_,  NULL, ThreadRoutine,  this);
}

void Thread::Join()
{
    pthread_join(threadId_,  NULL);
}

void *Thread::ThreadRoutine( void *arg)
{
    Thread *thread =  static_cast<Thread *>(arg);
    thread->Run();
     if (thread->autoDelete_)
         delete thread;
     return  NULL;
}

void Thread::SetAutoDelete( bool autoDelete)
{
    autoDelete_ = autoDelete;
}

void Thread::Run()
{
    func_();
}

Thread_test.cpp:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
 
#include  "Thread.h"
#include <boost/bind.hpp>
#include <unistd.h>
#include <iostream>
using  namespace std;

class Foo
{
public:
    Foo( int count) : count_(count)
    {
    }

     void MemberFun()
    {
         while (count_--)
        {
            cout <<  "this is a test ..." << endl;
            sleep( 1);
        }
    }

     void MemberFun2( int x)
    {
         while (count_--)
        {
            cout <<  "x=" << x <<  " this is a test2 ..." << endl;
            sleep( 1);
        }
    }

     int count_;
};

void ThreadFunc()
{
    cout <<  "ThreadFunc ..." << endl;
}

void ThreadFunc2( int count)
{
     while (count--)
    {
        cout <<  "ThreadFunc2 ..." << endl;
        sleep( 1);
    }
}


int main( void)
{
    Thread t1(ThreadFunc);
    Thread t2(boost::bind(ThreadFunc2,  3));
    Foo foo( 3);
    Thread t3(boost::bind(&Foo::MemberFun, &foo));
    Foo foo2( 3);
    Thread t4(boost::bind(&Foo::MemberFun2, &foo2,  1000));

    t1.Start();
    t2.Start();
    t3.Start();
    t4.Start();

    t1.Join();
    t2.Join();
    t3.Join();
    t4.Join();


     return  0;
}


注意:Thread类不再是虚基类,run() 也不是虚函数,Thread 有个成员ThreadFunc func_,此时不再是通过继承基类来重新实现run(),进而实现多态;而是通过绑定不同的函数指针到func_ 上来实现不同的行为。我们既可以绑定一般的全局函数,也可以绑定其他类里面的成员函数,操作很方便。此外,Thread t3, t4 不能绑定到同一个类对象foo 上,因为此时MemFun() 和MemFun2() 都会去访问同一个对象foo的count_ ,就会出现问题了。


假设TcpServer是一个网络库,如何使用它呢?那要看它是如何实现的:

C编程风格:注册三个全局函数到网络库,网络库函数的参数有函数指针类型,里面通过函数指针来回调。

面向对象风格:用一个EchoServer继承自TcpServer(抽象类),实现三个纯虚函数接口OnConnection, OnMessage, OnClose。通过基类指针调用虚函数实现多态。

基于对象风格:用一个EchoServer包含一个TcpServer(具体类)对象成员server,在构造函数中用boost::bind 来注册三个成员函数,如server.SetConnectionCallback(boost::bind(&EchoServer::OnConnection, ...)); 也就是设置了server.ConnectionCallback_ 成员,通过绑定不同的函数指针,调用server.ConnectionCallback_() 时就实现了行为的不同。如下所示。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class EchoServer
{
public:
    EchoServer()
    {
        server_.SetConnectionCallback(boost::bind(&EchoServer::OnConnection, ...));
                                      ...
    }
     void OnConnection()
    {
        ..
    }

    TcpServer server_;
};


参考:
muduo manual.pdf
《linux 多线程服务器编程:使用muduo c++网络库》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值