0Pricing
C++ Academy · 课时

使用 PIMPL 隐藏实现

使用指向实现的指针惯用法隐藏实现细节

使用 PIMPL 隐藏实现 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。

PIMPL 惯用法

PIMPL = “指向实现的指针”。将类的私有数据移动到单独的 Impl 结构体中,并通过指针访问。

为什么使用 PIMPL?

优点:

  • 从头文件中隐藏实现细节
  • 减少编译时依赖
  • 添加私有成员时保持 ABI 稳定
  • 允许替换实现

基本结构

公共类持有一个指向 Impl 结构体的指针,该结构体仅在 .cpp 文件中定义。

// widget.h
class Widget {
public:
    Widget();
    ~Widget();
    void doSomething();
private:
    struct Impl;
    std::unique_ptr<Impl> pimpl_;
};

cpp 文件中的 Impl

Impl 结构体存放所有实际数据。

// widget.cpp
struct Widget::Impl {
    std::string name;
    int counter;
    // ... anything else, freely
};

Widget::Widget()
    : pimpl_(std::make_unique<Impl>()) {}

Widget::~Widget() = default;  // must be in .cpp where Impl is complete

void Widget::doSomething() {
    pimpl_->counter++;
}

cpp 中的析构函数

析构函数必须定义在 Impl 完整定义所在的 .cpp 文件中。否则 unique_ptr 无法删除不完整类型。

特殊成员函数

如有需要,还必须显式声明复制、移动和赋值操作。编译器生成的版本无法在头文件中处理不完整类型。

// widget.h
class Widget {
public:
    Widget(const Widget& other);
    Widget& operator=(const Widget& other);
    Widget(Widget&&) noexcept;
    Widget& operator=(Widget&&) noexcept;
    ~Widget();
};

性能成本

PIMPL 会在每次成员访问时增加一次间接访问和一次堆分配。对于频繁调用的方法,这可能产生影响——请务必通过测量确认。

更快的构建

以前包含标准库类型或昂贵依赖项的头文件,现在可以变得更加精简。修改 .cpp 文件时无需重新编译使用方。

带继承的 PIMPL

可以与继承结合使用,但会增加复杂性。公共类通常不继承任何类型;Impl 则可以自由使用继承。

变体

替代方案和改进方式:

  • 快速 PIMPL——使用放置 new 的内联存储
  • 稳定地址——在对象的整个生命周期内保持 Impl 已分配
  • 类型擦除——Impl 可以具有多态性

实际应用

以下项目大量使用 PIMPL:

  • Qt(每个 Widget 都采用 PIMPL)
  • 许多专有库
  • Boost(部分位置)

何时使用

在以下情况下使用 PIMPL:

  • 您希望跨版本保持 ABI 稳定
  • 您的头文件通过传递性包含了过多内容
  • 您公开了库的公共应用程序接口

何时跳过

在以下情况下跳过 PIMPL:

  • 该类是内部实现——没有使用方依赖其头文件
  • 性能开销比构建时间更重要
  • 该类规模很小或很少修改

快速检查

为什么 PIMPL 类的析构函数必须定义在 .cpp 文件中?

回顾

PIMPL 将私有数据移动到通过 unique_ptr 访问的 Impl 结构体中,从而隐藏实现。它以增加间接访问为代价,改善了 ABI 稳定性和构建速度。请在 Impl 完整定义所在的 .cpp 文件中定义特殊成员函数。

常见问题解答

「使用 PIMPL 隐藏实现」课时是免费的吗?

是的 — 「使用 PIMPL 隐藏实现」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。

「使用 PIMPL 隐藏实现」这节课中我会学到什么?

使用指向实现的指针惯用法隐藏实现细节 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C++ Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「使用 PIMPL 隐藏实现」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C++ Academy 课中编写并运行代码吗?

能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 仅头文件库与编译库
  2. API 版本管理与 ABI 稳定性
  3. 使用 PIMPL 隐藏实现
  4. 编写现代的仅头文件实用工具库
← 返回 C++ Academy