C++ Pimpl编程技法

代码参考:github

昨天在看EffectiveC++,提到一个C++编程技巧,Pimpl(pointer to implementation)。

简单的理解就是在公共接口里面封装私有数据与方法,class提供更好的封装,下面来看看具体实现。

Pimpl(pointer to implementation, 指向实现的指针)是一种常用的,用来对“类的接口与实现”进行解耦的方法。这个技巧可以避免在头文件中暴露私有细节(见下图1),因此是促进API接口与实现保持完全分离的重要机制。但是Pimpl并不是严格意义上的设计模式(它是受制于C++特定限制的变通方案),这种惯用法可以看作桥接设计模式的一种特例。

在类中使用Pimpl惯用法,具有如下优点:

降低耦合
信息隐藏
降低编译依赖,提高编译速度
接口与实现分离

比如说,假设我们有Book class,现在为他添加一个实现细节,并封装到BookImpl类中:

// Book.h

#ifndef __BOOK_H__
#define __BOOK_H__
class Book
{
    public:
        Book();
        ~Book();
        void print();

    private:
        class BookImpl;
        BookImpl* pimpl;
};
#endif

为了实现接口与实现分离,这里的私有成员类对Book中的接口完成进一步封装:

//BookImpl.h

#ifndef __BOOKIMPL_H__
#define __BOOKIMPL_H__
#include "Book.h"
#include <iostream>
#include <string>
class Book::BookImpl
{
    public:
        void print();
    private:
        std::string content_;
        std::string titil_;
};
#endif

最后来看看实现,所有的共有接口都由BookImpl来实现:

//Book.cpp

#include "Book.h"
#include "BookImpl.h"

Book::Book()
{
    pimpl = new BookImpl();
}
Book::~Book()
{
    delete pimpl;
}
void Book::print()
{
    pimpl->print();
}
void Book::BookImpl::print()
{
    std::cout<<"print in imple"<<std::endl;
}

用户在使用的时候并不知道内部的构造,调用的时候就正常调用即可:

//main.cpp

#include "Book.h"
int main()
{
    Book book;
    book.print();

    return 0;
}

由于Pimpl解除了接口与实现之间的耦合关系,从而降低文件间的编译依赖关系,Pimpl也因此常被称为“编译期防火墙“ 。

顺便贴一下cppreference中的代码:

#include <iostream>
#include <memory>
#include <experimental/propagate_const>

// interface (widget.h)
class widget {
    class impl;
    std::experimental::propagate_const<std::unique_ptr<impl>> pImpl;
 public:
    void draw() const; // public API that will be forwarded to the implementation
    void draw();
    bool shown() const { return true; } // public API that implementation has to call
    widget(int);
    ~widget(); // defined in the implementation file, where impl is a complete type
    widget(widget&&) = default;  // Note: calling draw() on moved-from object is UB
    widget(const widget&) = delete;
    widget& operator=(widget&&); // defined in the implementation file
    widget& operator=(const widget&) = delete;
};

// implementation (widget.cpp)
class widget::impl {
    int n; // private data
 public:
    void draw(const widget& w) const {
        if(w.shown()) // this call to public member function requires the back-reference 
            std::cout << "drawing a const widget " << n << '\n';
    }
    void draw(const widget& w) {
        if(w.shown())
            std::cout << "drawing a non-const widget " << n << '\n';
    }
    impl(int n) : n(n) {}
};
void widget::draw() const { pImpl->draw(*this); }
void widget::draw() { pImpl->draw(*this); }
widget::widget(int n) : pImpl{std::make_unique<impl>(n)} {}
widget::~widget() = default;
widget& widget::operator=(widget&&) = default;

// user (main.cpp)
int main()
{
    widget w(7);
    const widget w2(8);
    w.draw();
    w2.draw();
}

参考:
http://blog.csdn.net/lihao21/article/details/47610309
http://en.cppreference.com/w/cpp/language/pimpl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值