博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面向对象编程风格 VS 基于对象编程风格(boost::bind/function)
阅读量:3603 次
发布时间:2019-05-21

本文共 6989 字,大约阅读时间需要 23 分钟。

分类:
580人阅读
(2)
收藏

本文主要通过实现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;
}
注意: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++网络库》
你可能感兴趣的文章
日均 5 亿查询量的京东订单中心,为什么舍 MySQL 用 ES ?
查看>>
Java 并发高频面试题:聊聊你对 AQS 的理解?
查看>>
写给工程师的 MySQL 面试高频 100 问!
查看>>
用 Spring 的 BeanUtils 前,建议先了解这几个坑!
查看>>
分布式 id 生成器
查看>>
面试官:Kafka 如何优化内存缓冲机制造成的频繁 GC 问题?
查看>>
【基于日均百万交易的订单系统】从 0 开始带你成为消息中间件实战高手!
查看>>
面试官:每秒上千订单的场景下,如何对分布式锁进行高并发优化?
查看>>
如何设计一个电商平台积分兑换系统?
查看>>
fastjson 漏洞导致服务瘫痪?先别忙升级,真相是它!
查看>>
产品经理相亲图鉴
查看>>
Redis 分布式锁的正确实现方式(Java版)
查看>>
Redis 到底是怎么实现“附近的人”这个功能的?
查看>>
最近面试 Java 后端开发的感受以及给候选人的一些建议!
查看>>
一个日均百万交易订单系统的整体架构、业务流程及负载情况?
查看>>
ArrayList 插入1000万条数据之后,我怀疑了jvm...
查看>>
【案例分析】分布式系统的接口幂等性设计!
查看>>
从一个程序员的角度告诉你:“12306”有多牛逼?
查看>>
MySQL 性能优化:8 种常见 SQL 错误用法!
查看>>
什么是读写锁?微服务注册中心是如何进行读写锁优化的?
查看>>