代码参考: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