PIMPL(pointer to implementation)是一种常用的,用来对“类的接口与实现”进行解耦的方法。pimpl具有如下优点:
为了实现pimpl模式,我们先来看一种普通的类的设计方法。
假如我们要设计一书籍类Book,Book包含目录属性,并提供打印书籍信息的对外接口,Book设计如下:
class Book
{
public:
void print();
private:
std::string m_Contents;
}
Book的使用者只需要知道print()接口,便可以使用Book类,看起来一切都很美好。
然而,当某一天,发现Book需要增加一标题属性,对Book类的修改如下:
class Book
{
public:
void print();
private:
std::string m_Contents;
std::string m_Title;
}
虽然使用print()接口仍然可以直接输出书籍的信息,但是Book类的使用者却不得不重新编译所有包含Book类头文件的代码。
为了隐藏Book类的实现细节,实现接口与实现的真正分离,可以使用pimpl模式。
/* public.h */
class Book
{
public:
Book();
~Book();
void print();
private:
class BookImpl;
BookImpl* m_p;
};
为简单实现起见,Book类省略了拷贝构造函数和拷贝赋值函数。在实际应用中,应该对这两个函数进行定义。
在对外的头文件public.h中,只包含Book类的外部接口,将真正的实现细节被封装到BookImpl类。为了不对外暴露BookImpl类,将其声明为Book类的内嵌类,并声明为private。
BookImpl类的头文件如下。
/* private.h */
#include "public.h"
#include <iostream>
class Book::BookImpl
{
public:
void print();
private:
std::string m_Contents;
std::string m_Title;
};
private.h并不需要提供给Book类的使用者,因此,如果往后需要重新设计书籍类的属性,外界对此一无所知,从而保持接口的不变性,并减少了头文件之间的依赖关系。
/* book.cpp */
#include "private.h"
#include "public.h"
Book::Book()
{
m_p = new BookImpl();
}
Book::~Book()
{
delete m_p;
}
void Book::print()
{
m_p->print();
}
/* then BookImpl functions */
void Book::BookImpl::print()
{
std::cout << "print from BookImpl" << std::endl;
}
使用Book类的接口的方法如下:
/* main.cpp */
#include "public.h"
int main()
{
Book book;
book.print();
return 0;
}
可以使用下图来说明pimpl模式在以上Book类设计的作用:
pimpl也因此常被称为“编译器防火墙“ 。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/lihao21/article/details/47610309