本文主要通过实现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 的原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
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 ( int, int)> fp2 = boost::bind(&Foo::memberFunc, &foo, 0. 5, _1, _2); fp2( 100, 200); boost::function< void ( int, int)> fp3 = boost::bind(&Foo::memberFunc, boost::ref(foo), 0. 5, _1, _2); fp3( 55, 66); 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; } |
假设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++网络库》