首页 > 其他 > 详细

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

时间:2019-06-11 21:58:45      阅读:113      评论:0      收藏:0      [点我收藏+]

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

介绍

面向对象的三大特点(封装,继承,多态)缺一不可。

通常“基于对象”是使用对象,但是无法利用现有的对象模板产生新的对象类型,继而产生新的对象,也就是说“基于对象”没有继承的特点。而“多态”表示为父类类型的子类对象实例,没有了继承的概念也就无从谈论“多态”。

现在的很多流行技术都是基于对象的,它们使用一些封装好的对象,调用对象的方法,设置对象的属性。但是它们无法让程序员派生新对象类型。他们只能使用现有对象的方法和属性。

所以当你判断一个新的技术是否是面向对象的时候,通常可以使用后两个特性来加以判断。“面向对象”和“基于对象”都实现了“封装”的概念,但是面向对象实现了“继承和多态”,而“基于对象”没有实现这些。

本文主要通过实现Thread类来展现两种编程风格的不同点。

面向对象风格

技术分享图片

Noncopyable.h

#pragma once

namespace wd
{

class Noncopyable
{
protected:
    Noncopyable(){}
    ~Noncopyable() {}

    Noncopyable(const Noncopyable &) = delete;
    Noncopyable & operator=(const Noncopyable &) = delete;
};

}//end of namespace wd

Thread.h

#pragma once

#include "Noncopyable.h"
#include <pthread.h>

namespace wd
{

class Thread 
: Noncopyable
{
public:
    Thread()
    : _pthid(0)
    , _isRunning(false)
    {}

    virtual ~Thread();

    void start();
    void join();

private:
    virtual void run() = 0;
    static void * threadFunc(void *);//没有隐含的this 指针

private:
    pthread_t  _pthid;
    bool _isRunning;
};

}//end of namespace wd

Thread.cc

#include "Thread.h"

#include <stdio.h>
#include <errno.h>
#include <iostream>
using std::cout;
using std::endl;

namespace wd
{

Thread::~Thread()
{
    if(_isRunning) {
        //pthread_detach(_pthid);   
        _isRunning = false;
    }
    cout << "~Thread()" << endl;
}

void Thread::start()
{
    if(pthread_create(&_pthid, nullptr, threadFunc, this)) {
        perror("pthread_create");
        return;
    }

    _isRunning = true;
}

void Thread::join()
{
    if(_isRunning) {
        pthread_join(_pthid, nullptr);
        _isRunning = false;
    }
}

void * Thread::threadFunc(void * arg)
{
    Thread * pthread = static_cast<Thread*>(arg);
    if(pthread)
        pthread->run();

    return nullptr;
}

}//end of namespace wd

TestThread.cc

#include "Noncopyable.h"
#include "Thread.h"

#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <memory>
using namespace std;


class Mythread
: public wd::Thread
{
public:
    ~Mythread() {   cout << "~Mythread()" << endl;}

private:
    void run() override
    {
        ::srand(::clock());
        int cnt = 10;
        while(cnt--) {
            int number = ::rand() % 100;
            cout << "sub thread " << pthread_self() 
                 << ": get a number = " << number << endl;
            ::sleep(1);
        }
    }

};
             
 
int main(void)
{
    cout << "main thread " << pthread_self() << endl;

    unique_ptr<wd::Thread> mythread(new Mythread());
    mythread->start();
    mythread->join();

    return 0;
}

Tips

  1. Thread类是虚基类,MyThread类通过继承实现虚函数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指针,故实现一个静态成员函数static void * threadFunc(void * arg),在里面调用run(),此外参数arg我们传递this指针,在派生类中将指针转换为基类指针来调用run()

  1. 把run()实现为private,目的为了不让用户直接调用,否则违背了线程的初衷。

基于对象风格

技术分享图片

Thread.cc

#pragma once

#include "Noncopyable.h"
#include <pthread.h>
#include <functional>

namespace wd
{

class Thread 
: Noncopyable
{
public:
    using ThreadCallback = std::function<void()>;

    Thread(ThreadCallback && cb)
    : _pthid(0)
    , _isRunning(false)
    , _cb(std::move(cb))
    {}

    ~Thread();

    void start();
    void join();

private:
    static void * threadFunc(void *);

private:
    pthread_t  _pthid;
    bool _isRunning;
    ThreadCallback _cb;
};

}//end of namespace wd

TestThread.cc

#include "Thread.h"

#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <memory>
using namespace std;


class MyTask 
{
public:
    ~MyTask() { cout << "~MyTask()" << endl;}

    void process() 
    {
        ::srand(::clock());
        int cnt = 10;
        while(cnt--) {
            int number = ::rand() % 100;
            cout << "sub thread " << pthread_self() 
                 << ": get a number = " << number << endl;

            ::sleep(1);
        }
    }
};
             
 
int main(void)
{

    cout << ">> main thread " << pthread_self() << endl;

    MyTask task;

    //如果是以指针的方式传递对象,要保证在执行process方法时,
    //该对象生命周期没有结束;如果结束,执行会出错
    //
    //绑定对象时,也可以以值传递方式传递对象(多析构一次)
    unique_ptr<wd::Thread> mythread(
        new wd::Thread(std::bind(&MyTask::process, &task)));
    mythread->start();
    mythread->join();

    return 0;
}

Tips

bind/function 实现转换函数接口。

  1. 如果绑定的是一般的函数,则bind 中的参数中不再需要this指针,当然一般函数也没有类名前缀。
  2. 如果绑定的成员函数,则bind中的参数需要this指针,而且需要加上类名和取地址符号。
  3. Thread类不再是虚基类,run() 也不是虚函数,Thread 有个成员threadFunc,此时不再是通过继承基类来重新实现run(),进而实现多态;而是通过绑定不同的函数指针到threadFunc上来实现不同的行为。
  4. 我们既可以绑定一般的全局函数,也可以绑定其他类里面的成员函数,操作很方便。

小结

一个object-based设计可能比一个对等的objectoriented设计速度更快而且空间更紧凑,速度快是因为所有的函数引发操作都在编译时期解析完成,对象构建起来时不需要设置virtual机制;空间紧凑是因为每一个class object不需要负担传统上为了支持virtual机制而需要的额外负荷(virtual table),不过OB设计比较没有弹性。


基于对象的语言

  • 基于对象的语言支持对象和封装的使用。

  • 它们不支持继承或多态或两者

  • 基于对象的语言不支持内置对象。
  • Javascript,VB是对象基础语言的示例。

面向对象的语言

  • 面向对象的语言支持Oops的所有功能,包括继承和多态。
  • 它们支持内置对象。
  • C#,Java,VB。Net是面向对象语言的示例。

参考:

  1. https://www.tutorialspoint.com/what-is-the-difference-between-object-oriented-programming-and-object-based-programming
  2. https://blog.csdn.net/daaikuaichuan/article/details/85945208
  3. 《深度探索C++对象模型》

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

原文:https://www.cnblogs.com/Mered1th/p/11006299.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!