C++ 编译期封装-Pimpl技术

本文介绍了Pimpl技术,它是一种现代C++技术,通过私有成员指针隐藏类的内部实现数据。文中阐述了其基本应用,给出代码示例,并分析了适用场景。该技术能减少依赖、分离接口与实现、使用惰性分配,但也有额外内存和操作开销,适合对性能/内存要求不敏感的领域。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Pimpl技术——编译期封装

 

Pimpl 意思为“具体实现的指针”(Pointer to Implementation),

它通过一个私有的成员指针,将指针所指向的类的内部实现数据进行隐藏,

是隐藏实现,降低耦合性和分离接口实现的一个现代 C++ 技术,并有着“编译防火墙(compilation firewall)”的名头。

 

Pimpl技术的基本应用

其中利用了C++11的std::unique_ptr来让Impl指针的内存更易受控制。

此外由于声明了析构函数,导致默认的移动构造/赋值函数不能生成,若默认行为符合自己的需求,则需显式声明 = default

(当只在.h里,Impl是个不完整的类型,所以无法在.h类直接 = default,而是在.h声明,在.cpp使= default)

若需要给类提供拷贝性质的函数,需要额外花点心思处理std::unique_ptr(该智能指针不支持拷贝)。

// my_class.h
#pragma once
#include <memory>

class my_class {
    //  ... 所有的公有/保护接口都可以放在这里 ...
    my_class();
    ~my_class();
    my_class(my_class&& v);    //移动构造
    my_class& operator=(my_class&& v);    //移动赋值
private:
    class Impl; 
    std::unique_ptr<Impl> pimpl;
};
// my_class.cpp
// ...include其它要依赖的头文件...
#include "my_class.h"

class my_class::Impl {
  // 在这里定义所有私有变量和方法(换句话说是my_class类的具体实现细节内容)
  // 现在可以改变实现,而依赖my_class.h的其他类无需重新编译...
};

my_class::my_class():pimpl(std::make_unique<Impl>()){
    // ...初始化pimpl... 
}
my_class::~my_class() = default;
my_class::my_class(my_class&& v) = default;
my_class::my_class& operator=(my_class&& v) = default;

 

代码示例

//View.h文件
#pragma once
#include <memory>

class View
{
public:
    View();
    ~View();
    View(View&& v);
    View& operator=(View&& v);
    void display();
private:
    class Impl;
    std::unique_ptr<Impl> pimpl; 
};
//View.cpp文件
#include <iostream>
#include <string>
#include "View.h"

/////////////////////////////////////////////////////////
//下面是View::Impl的定义,也就是体现了View类的具体实现细节

class View::Impl {
    std::string name;
public:
    Impl();
    void printName();
};

View::Impl::Impl(){
    name = "DefaultName";
}

void View::Impl::printName(){
    std::cout << "this is my name:" << name;
}

///////////////////////////////////////////////////////////
//下面是View类接口的实现

View::View():pimpl(std::make_unique<Impl>()){
}

View::~View() = default;
View::View(View&& v) = default;
View& View::operator = (View&& v) = default;

void View::display(){
    pimpl->printName();
}

 

什么时候使用Pimpl技术?

可以看到Pimpl拥有如下优点:

  • 减少依赖项(降低耦合性):其一减少原类不必要的头文件的依赖,加速编译;其二对Impl类进行修改,无需重新编译原类。

  • 接口和实现的分离(隐藏了类的实现)私有成员完全可以隐藏在共有接口之外,给用户一个间接明了的使用接口,尤其适合闭源API设计。

  • 可使用惰性分配技术:类的某部分实现可以写成按需分配或者实际使用时再分配,从而节省资源。

Pimpl也拥有一些缺点:

  • 每个类需要占用小小额外的指针内存。

  • 每个类每次访问具体实现时都要多一个间接指针操作的开销,并且再使用、阅读和调试上都可能有所不便。

可以说,在性能/内存要求不敏感(非极端底层)的领域,Pimpl技术可以有相当不错的发挥和作用。

转载于:https://www.cnblogs.com/KillerAery/p/9539705.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值