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


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

    介绍

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

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

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

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

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

    面向对象风格

    OO_PC

    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,目的为了不让用户直接调用,否则违背了线程的初衷。

    基于对象风格

    BO_PC

    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++对象模型》
  • 相关阅读:
    Java集合——Map接口
    Django 创建一个返回当前时间的页面
    python 练习 后台返回当前时间
    python 练习 simple_server 判断路径及返回函数
    通过 docker 来搭建 Jenkins
    Bitbucket 触发内网 Jenkins Build
    jQuery 扩展方法
    HTML 练习滑动
    HTML 练习淡入淡出
    HTML 练习显示隐藏
  • 原文地址:https://www.cnblogs.com/Mered1th/p/11006299.html
Copyright © 2020-2023  润新知