前言
近段时间在学习Qt编程,在学习中发现在很多生成的代码中都有先定义一个Ui命名空间,在Ui命名空间中定义一个类,然后接下来又给出一个同名的类的定义,对这种用法由于在之前C++的学习中并没有使用过,因此对该用法进行了一定的研究,结合老师的讲解,在此谈谈对该设计模式的理解。初次记录博客,如有错误,还请见谅。
概念
Pimpl
(pointer to implementation,
指向实现的指针
)是一种常用的,用来对“类的接口与实现”进行解耦的方法。这个技巧可以避免在头文件中暴露私有细节,因此是促进API接口与实现保持完全分离的重要机制。通过在类中定义接口,将私有数据成员封装在另一个类中的方式实现接口与实现的分离。
特点
由于
当头文件改变时,#include该文件的任何文件都需要重新编译,
即使这些更改仅适用于类的私有成员,情况也是如此
。 PIMPL设计模式
通过接口和实现的分离,可以
降低模块耦合和编译依赖,提高编译速度
。当类的内部改变时,不需要重新编译调用的程序。
代码实例
cimplement.h文件
#ifndef CIMPLEMENT_H
#define CIMPLEMENT_H
class CImplement //定义一个实现类
{
public:
CImplement();
void doSomethingReal();
};
#endif // CIMPLEMENT_H
c.h文件
#ifndef C_H
#define C_H
class CImplement; //前置声明
class C
{
public:
C();
~C();
void doSomething();
private:
CImplement * c; /*PIMPL设计格模式关键,在C类中定义一个私有指向实现类的指针数据成员。
通过该指针实现一系列操作,那么在改变操作时只需要重新编译cimplement.h即可*/
};
#endif // C_H
cimplement.cpp文件
#include "cimplement.h"
#include <iostream>
using namespace std;
CImplement::CImplement() //空的构造函数
{
}
void CImplement::doSomethingReal() //真正的doSomething函数实现方式
{
cout<<"C call CImplement do something"<<endl;
}
c.cpp文件
#include "c.h"
#include "cimplement.h"
C::C():c(new CImplement) //使用括号赋值法为内部指针成员赋值,用new创建
{
}
C::~C() //析构函数,主动通过delete删除new创建的对象,释放内存
{
delete c;
}
void C::doSomething() //通过内部指针调用真正实现函数
{
c->doSomethingReal();
}
main.cpp文件
#include <QCoreApplication>
#include "c.h"
int main(int argc, char *argv[])
{
C c; //创建一个C类对象
c.doSomething(); /*调用doSomething函数,但实质是调用cimplement类中的doSomethingReal函数
当需求发生改变时,例如需要修改输出语句时,只需要修改cimplement类中的函数
这样main文件不需要重新编译,在大型工程中更能体现这种设计模式的优越性*/
return 0;
}
程序运行结果
后记
以上就是我个人的一些理解,并没有多深奥,只是起一个抛砖引玉的作用,总之该设计模式在后面大规模的程序中经常用到,因此掌握是非常有必要的。另外如果哪些地方见解有误,还请批评指正。