【muduo】面向对象编程风格 VS 基于对象编程风格(std::bind/function)

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

一、面向对象编程风格

在这里插入图片描述

#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;
}

【Note】:

  • Thread类是虚基类,TestThread类继承来实现虚函数run()。

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

  • 把run()实现为private是为了不让用户直接调用,因为这样根本就没有产生线程调度。

  • 注意区分线程与线程对象,设置autoDetele_ 成员也是为了当线程结束时能够立刻销毁线程对象。在main函数内,主线程pthread_join()等待线程结束;run()结束后会delete 掉线程对象,否则要一直等到main函数结束才会被自动销毁。

二、基于对象编程风格

1、std::bind/function的使用

#include <iostream>
using namespace std;
class Foo
{
 public:
  void methodA();
  void methodInt(int a);
};
class Bar
{
 public:
  void methodB();
};

std::function<void()> f1; // 无参数,无返回值

Foo foo;
f1 = std::bind(&Foo::methodA, &foo);
f1(); // 调用 foo.methodA();
Bar bar;
f1 = std::bind(&Bar::methodB, &bar);
f1(); // 调用 bar.methodB();

f1 = std::bind(&Foo::methodInt, &foo, 42);
f1(); // 调用 foo.methodInt(42);

std::function<void(int)> f2; // int 参数,无返回值
f2 = std::bind(&Foo::methodInt, &foo, _1);
f2(53); // 调用 foo.methodInt(53);

2、基于对象的编程风格

在这里插入图片描述

#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(std::bind(ThreadFunc2, 3));
    Foo foo(3);
    Thread t3(std::bind(&Foo::MemberFun, &foo));
    Foo foo2(3);
    Thread t4(std::bind(&Foo::MemberFun2, &foo2, 1000));

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

    t1.Join();
    t2.Join();
    t3.Join();
    t4.Join();
    
    return 0;
}

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值