PImpl:Pointer to Implementation

Pimpl(Pointer to implementation)是一种C++编程技术,用于将类的实现细节与其接口分离。通常情况下,类的实现细节会暴露在类的头文件中,这会增加代码的复杂性并使得类的修改和维护变得困难。使用Pimpl技术,可以在类的头文件中只暴露必要的接口,而将具体实现细节放在单独的实现文件中,通过指向这个实现的指针来访问。

Pimpl技术可以带来以下好处:

  1. 将类的实现细节隐藏起来,使得类的接口更加简洁和清晰。
  2. 降低了代码的耦合性,修改类的实现不会影响用户代码。
  3. 可以减小编译依赖关系,减少编译时间。
  4. 通过使用智能指针(如std::unique_ptr)可以避免内存泄漏和删除对象时的不一致性问题。

使用Pimpl技术也有一些缺点,如额外的内存开销和性能损耗等。因此,在实际应用中需要根据情况来权衡是否使用这种技术。

在实际项目中,当某个类作为接口需要导出时,可以考虑使用Pimpl,这样可以只暴露必要的接口,隐藏实现细节,降低耦合。

以下是Pimpl的例子:

// ----------------------
// interface (widget.hpp)
#include <experimental/propagate_const>
#include <iostream>
#include <memory>
 
class widget
{
    class impl;
    std::experimental::propagate_const<std::unique_ptr<impl>> pImpl;
public:
    void draw() const; // public API that will be forwarded to the implementation
    void draw();
    bool shown() const { return true; } // public API that implementation has to call
 
    widget(); // even the default ctor needs to be defined in the implementation file
              // Note: calling draw() on default constructed object is UB
    explicit widget(int);
    ~widget(); // defined in the implementation file, where impl is a complete type
    widget(widget&&); // defined in the implementation file
                      // Note: calling draw() on moved-from object is UB
    widget(const widget&) = delete;
    widget& operator=(widget&&); // defined in the implementation file
    widget& operator=(const widget&) = delete;
};
 
// ---------------------------
// implementation (widget.cpp)
// #include "widget.hpp"
 
class widget::impl
{
    int n; // private data
public:
    void draw(const widget& w) const
    {
        if (w.shown()) // this call to public member function requires the back-reference 
            std::cout << "drawing a const widget " << n << '\n';
    }
 
    void draw(const widget& w)
    {
        if (w.shown())
            std::cout << "drawing a non-const widget " << n << '\n';
    }
 
    impl(int n) : n(n) {}
};
 
void widget::draw() const { pImpl->draw(*this); }
void widget::draw() { pImpl->draw(*this); }
widget::widget() = default;
widget::widget(int n) : pImpl{std::make_unique<impl>(n)} {}
widget::widget(widget&&) = default;
widget::~widget() = default;
widget& widget::operator=(widget&&) = default;
 
// ---------------
// user (main.cpp)
// #include "widget.hpp"
 
int main()
{
    widget w(7);
    const widget w2(8);
    w.draw();
    w2.draw();
}

 

参考:

【1】https://blog.csdn.net/qq_21438461/article/details/132900415

【2】https://en.cppreference.com/w/cpp/language/pimpl

 

posted @ 2024-04-26 08:57  快雪  阅读(54)  评论(0编辑  收藏  举报