pimpl即 pointer to implementation,是“指向实现的指针”缩写,这一设计模式主要是用于避免在头文件中暴露私有细节,降低编译依赖,促进API接口和实现的完全分离。
接下来将通过例子来解释该模式的实现方法:
(1)CIMPL.h文件
#include <iostream>
#include "cimpl.h"
using namespace std;
void CIMPL::doSomethingReal()
{
cout<<"C call CIMPL do something"<<endl;
}
(2)CIMPL.cpp文件
#ifndef CIMPL_H
#define CIMPL_H
class CIMPL//该类写具体的实现方法,等着被调用
{
public:
void doSomethingReal();
};
#endif // CIMPL_H
(3)C.h文件
#ifndef C_H
#define C_H
class CIMPL;
class C
{
public:
C();
~C();
void doSomething();
private:
CIMPL * cImpl;//含有指向CIMPL类的对象指针
};
#endif // C_H
(4)C.cpp文件
#include "c.h"
#include "cimpl.h"
C::C():
cImpl(new CIMPL)//冒泡赋值法,等价于cImpl=new CIMPL();
//此时就会给类C中的成员指针绑定上一个实例对象
{
}
C::~C(){
delete cImpl;//在C++中new 与delete是一一对应的
//在JAVA中则不需要自己写delete,有
//自动回收机制
}
void C::doSomething(){
cImpl->doSomethingReal();//通过指针来调用
}
(5)main.cpp文件
#include <iostream>
#include "c.h"
using namespace std;
int main()
{
C c;
c.doSomething();/*C间接调用CIMPL类中的方法,
对于用户而言,即使之后CIMPL类
中的函数发生变化,此处的调用也不会
发生变化*/
return 0;
}
在所给的代码中,有一个类CImplement,其中定义了方法dosomethingreal();类同时类C有CImplement类的指针,在主函数中只用实例一个C类对象,此时调用类C的构造函数,而在类C的构造函数中又将CIMPL类指针与CIMPL类对象绑定起来,那么就可以通过该指针调用CIMPL类中的方法dosomethingreal,再将该方法包装为dosomething即可,这样即使以后CImplement中的方法发生了变化,在主函数中也不用改变具体的代码,比较简洁方便。
在QT中的很多源码里面,也是采用了这种编码风格。打开QT,创建一个工程,就会生成一端代码,这段代码的功能是显示一个窗口,仔细分析,其实自动生成的这段代码也是采用了PIMPL思想。
(1)mainwindown.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow//公有继承,Qmainwindown相当于具体的实现类,这里采用继承是出于安全性考虑,为用户封装了类名
{
Q_OBJECT//引入信号与槽机制
public:
explicit MainWindow(QWidget *parent = 0);//可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。
//声明为explicit的构造函数不能在隐式转换中使用。
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
(2)main.cpp文件
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
(3)mainwindown.cpp文件
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),//Qmainwindown相当于之前的Cimlent类
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}