C++ Pimpl惯用法(桥接模式特例)智能指针

Pimpl惯用法

Pimpl术语,即“pointer to implementation”(指向实现的指针),由Jeff Summer最先引入。该技巧可以避免在头文件中暴露私有细节,是促进API接口和实现保持完全分离的重要机制。(在将接口提供给别人时经常使用的一个技巧)

Pimpl并不是严格意义上的设计模式,而是桥接模式的一种特例。

Pimpl将类的数据成员定义为指向某个已经声明过的类型的指针,如上面例子中的impl。这里,类型仅作为名字引入,没有被完整定义,只需要前向声明即可,隐藏可以将该类型定义隐藏在.cpp文件中。该指针也称为不透明指针,因为用户无法看到所指对象细节。

示例

:“自动定时器”(AutoTimer)API,对象被销毁时打印出生存时间。

// autotimer.h
#include <string>

class AutoTimer // 接口类
{
public:
    explicit AutoTimer(const std::string &name);
    ~AutoTimer();

private:
    class Impl; // 前置声明
    Impl *impl; // 通过私有内嵌类, 将实现细节封装到内嵌类中
};

// autotimer.cpp
#include "autotimer.h"
#include <iostream>
#if _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif

class AutoTimer::Impl // 实现类
{
public:
    double GetElapsed() const
    {
#ifdef _WIN32
        return (GetTickCount() - startTime_) / 1e3;
#else
        struct timeval end_time;
        gettimeofday(&end_time, NULL);
        double t1 = startTime_.tv_usec / 1e6 + startTime_.tv_sec;
        double t2 = end_time.tv_usec / 1e6 + end_time.tv_sec;
        return t2 - t1;
#endif
    }

    std::string name_;
#ifdef _WIN32
     DWORD starTime_;
#else
    struct timeval startTime_;
#endif
};

AutoTimer::AutoTimer(const std::string &name) :
    impl_(new AutoTimer::Impl())
{
    impl_->name_ = name;
#ifdef _WIN32
    imp_->startTime_ = GetTickCount();
#else
    gettimeofday(&impl_->startTime, NULL);
#endif
}

AutoTimer::~AutoTimer()
{
    std::cout << impl_->name_ << ": took " << impl_->GetElapsed()
        << " secs" << std::endl;
    delete impl_;
    impl_ = NULL;
}

Pimpl与智能指针

使用裸指针指向Impl类,容易忘记在析构时delete对象,或者在对象分配前就进行访问,从而造成错误。可以借助智能指针(smart pointer)解决该问题,具体来说,可采用shared_ptr(共享指针),或unique_ptr(域指针)指向Impl类对象。
两者区别:共享指针允许用户复制(接口类)对象,域指针不允许用户复制。

#include <memory>
#include <string>

class AutoTimer
{
public:
    explicit AutoTimer(const std::string &name);
    ~AutoTimer();

private:
    class Impl;//类的前置声明
    std::unique_ptr<Impl> impl_;
};

参考链接

桥接模式

Bridge是一种结构设计模式,可让您将一个大类或一组密切相关的类拆分为两个独立的层次结构(抽象和实现),这两个层次结构可以彼此独立开发。

定义比较抽象,可以认为,提供接口API 动态库,确定接口后不再修改,就是桥接模式的简单实现

调用方可以自由扩张,实现方也可以自由扩展,并且使用动态,在部署的时候,可以分别部署。

项目初期阶段确定接口
调用方在编译的时候有一个旧版本,或者实现一个假接口就可以开发。接口提供方可以同步进行开发(这个在项目中是个很普遍的做法)

设计模式桥接模式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值