面向对象的三大特点(封装,继承,多态)缺一不可。通常“基于对象”是使用对象,但是无法利用现有的对象模板产生新的对象类型,继而产生新的对象,也就是说“基于对象”没有继承的特点
。没有了继承的概念也就无从谈论“多态”。所以当你判断一个新的技术是否是面向对象的时候,通常可以使用后两个特性来加以判断。
面向对象的编程风格
#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_
#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;
}
#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;
}
Thread类是虚基类,TestThread类继承来实现虚函数run()。
根据 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()
。
把run()实现为private是为了不让用户直接调用,因为这样根本就没有产生线程调度。
注意区分线程与线程对象,设置autoDetele_成员也是为了当线程结束时能够立刻销毁线程对象。在main函数内,主线程pthread_join()等待线程结束;run()结束后会delete掉线程对象,否则要一直等到main函数结束才会被自动销毁。
基于对象编程风格
#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_
#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_();
}
#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() 时就实现了行为的不同`。
boost bind/function 实现转换函数接口
#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;
}