允许用户包含类,而不包括用于私有的标头

The*_*Man 5 c++ c++11

很抱歉这个漫长而令人困惑的标题.

我有这样的类头文件

#pragma once
#include <thread>
#include <boost/asio.hpp>
#include <another3rdpartylib/doodads.h>

class A {
public:
  A();
  Method1();
  Method2();
private:
  std::thread thread;
  boost::asio::socket socket;
  another3dpartylib::doodad gizmo;
}
Run Code Online (Sandbox Code Playgroud)

现在,班级的用户不会也不应该关心私人部分.如何在不拖动的情况下允许用户包含该类<thread>,<boost/asio.hpp>并且<another3rdpartylib/doodads.h>

从技术上讲,用户唯一应该关心的是sizeof(A).我错了吗?

Man*_*726 8

C++中分割接口和类实现的常用方法是使用指针实现(PIMPL)成语.

PIMPL惯用法通过将引用/指针存储到负责执行操作的类来封装类的实现,仅向用户提供类,即接口,该接口仅充当实现类的包装器.

例如:考虑一个为浮点运算实现极快堆栈的库.容器的界面非常简单:

class fast_stack
{
public:
    void push( float );
    float pop();
};
Run Code Online (Sandbox Code Playgroud)

但是由于这个库实现了极快的堆栈,它的实现基于极其复杂的库,内联汇编,brainfuck互操作性等.

该库的用户只想要一个堆栈,而不是一堆可怕的代码,库和依赖项.我们怎样才能隐藏所有的尖叫声,只为他提供一个简单而干净的界面?这就是PIMPL开始的地方:

//stack_inferno.hpp

#include <thread>
#include <Boost/ASIO>
... More monters here

class fast_stack_infernal_implementation
{
   std::thread* _mptr_thread_lcl;
   float******* _suicide_cache_memory_pool;
   ... etc etc

   void push( float elem )
   {
        //Please don't see this code, it could hurt your eyes
   }

   float pop()
   {
        // Same as above
   }
};



//fast_stack.hpp (Revisited)

class fast_stack_infernal_implementation; //Note the forward declaration. 

class fast_stack
{
public:
    void push( float );
    float pop();

private:
    std::unique_ptr<fast_stack_infernal_implementation> implm;
};



//fast_stack.cpp

#include "stack_inferno.hpp" //Tah daah!


fast_stack::fast_stack() : impl( new fast_stack_infernal_implementation() )
{
}

void fast_stack::push( float elem )
{
     implm->push( elem );
}

float fast_stack::push()
{
     return implm->pop();
}
Run Code Online (Sandbox Code Playgroud)

如您所见,PIMPL习语具有许多优点:

  • 向用户隐藏实现的复杂性,并仅提供接口.
  • 用户头文件(接口头文件)不包含实现头,因此对实现的更改不会导致重新编译孔库和用户代码.这对于库来说非常重要,因为库上的更改并不总是会破坏用户代码.

  • @CaptainObvlious实际上,每当我看到这个首字母缩略词拼写出来时,如果是"指向实现的指针".你能提供支持报价吗? (5认同)