面向对象编程风格 VS 基于对象编程风格
面向对象编程风格 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
- Thread类是虚基类,MyThread类通过继承实现虚函数run()。
- 我们先看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()
- 把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 实现转换函数接口。
- 如果绑定的是一般的函数,则bind 中的参数中不再需要this指针,当然一般函数也没有类名前缀。
- 如果绑定的成员函数,则bind中的参数需要this指针,而且需要加上类名和取地址符号。
- Thread类不再是虚基类,run() 也不是虚函数,Thread 有个成员threadFunc,此时不再是通过继承基类来重新实现run(),进而实现多态;而是通过绑定不同的函数指针到threadFunc上来实现不同的行为。
- 我们既可以绑定一般的全局函数,也可以绑定其他类里面的成员函数,操作很方便。
小结
一个object-based设计可能比一个对等的objectoriented设计速度更快而且空间更紧凑,速度快是因为所有的函数引发操作都在编译时期解析完成,对象构建起来时不需要设置virtual机制;空间紧凑是因为每一个class object不需要负担传统上为了支持virtual机制而需要的额外负荷(virtual table),不过OB设计比较没有弹性。
基于对象的语言
-
基于对象的语言支持对象和封装的使用。
-
它们不支持继承或多态或两者
-
基于对象的语言不支持内置对象。
-
Javascript,VB是对象基础语言的示例。
面向对象的语言
- 面向对象的语言支持Oops的所有功能,包括继承和多态。
- 它们支持内置对象。
- C#,Java,VB。Net是面向对象语言的示例。
参考: