首页 > 其他分享 >PIMPL

PIMPL

时间:2024-02-21 17:57:01浏览次数:25  
标签:头文件 实现 PIMPL 编译 细节 MyClass

PIMPL(Pointer to Implementation)本质上也属于设计模式的一种,PIMPL也称为 Opaque Pointer(不透明的指针)。主要目的是将一个类的 实现细节(private/protected 方法、成员)其对外的公共接口 分离出来,使得 实现细节 可以在不影响客户端代码的情况下进行更改。

这样做的好处主要有以下两点:

  1. 对外隐藏实现细节,尤其是隐藏对外提供的库的实现细节
  2. 降低编译依赖,从而减少重新编译的时间

PIMPL实现的要点:

  1. 前向声明一个内部嵌套类Impl及其指针
  2. 将具体实现细节(private/protected 方法、成员)转移到内部嵌套类Impl中

隐藏实现细节

具体场景

在实际工作的过程中,需要对外提供一些库以及相应的头文件供三方人员使用,假设某个库的头文件如下:

// MyClass.h
#include <string>
#include <iostream>

class MyClass {
public:
    MyClass();
    ~Myclass();
    void publicMethod();
    
private:
    void privateMethod();
    
private:
    std::string mName_;
};

三方人员只需要使用到我们暴露的公共接口即可,但是我们却不得不将上述头文件提供给他们,这会导致如下两个问题:

  1. 实现细节被暴露,三方人员可以看到整个类的实现细节
  2. 接口不稳定,如果我们对mName_的类型进行改动,或者增加了一些成员变量,虽然没有修改public下的接口,但是对于使用人员来说也要更新头文件
  3. 增加了使用者的依赖,如2所说,使用者只关心自己调用的接口,不希望因为实现细节更改导致自己需要进行更改,显然当前提供的头文件无法满足

解决办法-PIMPL

PIMPL的引入就是为了解决上述问题,按照PIMPL的实现要点修改上述头文件如下:

// MyClass.h
#include <string>
#include <iostream>

class MyClass {
public:
    MyClass();
    ~Myclass();
    void publicMethod();
    
private:
    struct Impl;
    Impl* pImpl_;
};

对应的源文件如下:

#include "MyClass.h"

void Myclass::publicMethod() {
	std::cout << "public method" << std::endl;
    // 调用具体实现细节
    pImpl_->privateMethod;
}
struct Myclass::Impl {
	void privateMethod() {
		std::cout << "private method" << std::endl; 
	}
    
    std::string mName_;
}

Myclass::Myclass() 
:pImpl_(new Impl)
{}

Myclass::~Myclass() {
	delete pImpl_;
}

可以看出,修改后的代码 MyClass 的实现细节被封装在 MyClass::Impl 中,MyClass 的头文件只包含了公共接口;从而保证了:

  1. 不暴露实现细节
  2. 实现细节的改动不影响使用者,因为使用者的头文件中并不包含具体实现

降低编译依赖

降低编译依赖是由于编译器的工作方式以及C++的分离编译机制所决定的。在典型的C++项目中,每个源文件都会被独立地编译成目标文件(通常是.o.obj文件)。这些目标文件之后由链接器(linker)将它们组合成可执行文件或库。

所以当我们对源文件的修改不涉及头文件中提供的公共接口,只需要重新编译源文件,而不需要重新编译使用者的代码;

举例如下:

假设使用者的代码编译结果为clien.o, 当我们只修改了 MyClass.cpp 中的具体实现,例如增加了一个成员变量,而没有改变 MyClass.h 中的声明,那么只需要重新编译 MyClass.cpp 文件:

$ g++ -c MyClass.cpp -o MyClass.o

之后,你可以链接 Client.o 与新生成的 MyClass.o

$ g++ Client.o MyClass.o -o myProgram

这样就不必重新编译使用者的源代码Client.cpp,因为它只依赖于 MyClass.h 的声明,而不依赖于 MyClass.cpp 中的实现。这是分离编译的优势之一。

标签:头文件,实现,PIMPL,编译,细节,MyClass
From: https://www.cnblogs.com/christopherJames/p/18025862/pImpl

相关文章

  • C++源码中司空见惯的PIMPL是什么?
    前言:C++源码中司空见惯的PIMPL是什么?用原始指针、std::unique_ptr和std::shared_ptr指向Implementation,会有什么不同?优缺点是什么?读完这篇文章,相信你能搞懂这种设计方式并将其运用于实践,也将更容易阅读源码。1.PIMPL是什么?PIMPL是PointertoIMPLementation的缩写,意思是指......
  • D. Effects of Anti Pimples
    D.EffectsofAntiPimples对于样例一:14出现2次9出现1次19出现12次规律:1.我们发现1与后面的组合的最大值等于数列的最大值,次数是2^(n-1),这是巧合吗?2.往下递推,我们可知2与后面的组合为2的倍数的最大值,次数为2^(n-2),...3.因此我们可以先算出每个位置的最大值,然后乘以相应......
  • CF1877D Effects of Anti Pimples
    计算每个数作为最大值的贡献,计算每个数作为最大值的次数。每个数作为最大值时的贡献显然是\(a_i\timescnt_i\),\(cnt_i\)为\(a_i\)在多少种染色方案中作为最大值出现,我们主要来对每个数求\(cnt_i\)。我们对于从\(1\)到\(n\)枚举元素,求出它和能被它染成绿色的所有元素中......
  • D. Effects of Anti Pimples
    D.EffectsofAntiPimplesChanekahasanarray$[a_1,a_2,\ldots,a_n]$.Initially,allelementsarewhite.Chanekawillchooseoneormoredifferentindicesandcolourtheelementsatthosechosenindicesblack.Then,shewillchooseallwhiteelementsw......
  • C++ Pimpl用法
    点击查看代码//定义成宏publicDefine.h//PIMPL模式声明#definePIMPL_DEFINE(Classname)\constClassname##Impl*GetImpl()const;\Classname##Impl*GetImpl();\std::unique_ptr<Classname##Impl>m_pData;//PIMPL模式实现#definePIMP......
  • 设计 C++ 接口文件的小技巧之 PIMPL
    C++里面有一些惯用法(idioms),如RAII,PIMPL,copy-swap、CRTP、SFINAE等。今天要说的是PIMPL,即PointerToImplementation,指向实现的指针。问题描述在实际的项目中,经常需要定义和第三方/供应商的C++接口。假如有这样一个接口文件:MyInterface.h#include<string>#include<li......
  • 利用PImpl在C++14中优雅调用C++17方法
    诉求你的工程由C++14写成,某天你看中了一个功能强大的三方库,一切都好除了该库仅支持C++17编译,对于比较复杂的三方库使用C++14进行重构工作量太大,有没有优雅的办法?实现历史总是惊人的相似,为了解决这一问题前人发明了PImpl编程方法用于隐藏class的实现细节,头文件中仅声明抽象class......
  • 09、OpenFoam中的PISO,SIMPLE和PIMPLE算法
    隐式:PISO半隐式:SIMPLE组合式:PIMPLE(PISO+SIMPLE)PISO算法PISO算法是一种常用于求解不可压缩流体流动问题的数值方法,它在OpenFOAM中被广泛应用。PISO算法的全称为PressureImplicitwithSplittingofOperators,即利用算子分裂的方法进行隐式求解压力和速度。PISO算法主要分为......
  • C++编程技巧: Pimpl
    Pimpl(Pointertoimplementation)是一种减少代码依赖和编译时间的C++编程技巧,其基本思想是将一个外部可见类(visibleclass)的实现细节(一般是所有私有的非虚成员)放在一个......
  • pimpl
    这种方法用于向用户隐藏实现细节例如存在库的头文件:classlib{public:lib();~lib();intfun();private:intfield1_;charfield2_;intfoo();......