您的位置:首页 > 编程语言

面向对象编程风格&基于对象编程风格

2014-10-29 10:37 381 查看
本文主要通过实现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 style="background-color: rgb(255, 204, 204);" class="highlight">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 (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;

}

注意: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_;

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: