为Pimpl使用不透明指针的更好方法

时间:2014-07-27 05:27:17

标签: c++ pointers pimpl-idiom

我正在使用来自不同供应商(C或C ++)的各种库,围绕嵌入式系统(固件级)的许多不同硬件库编写C ++包装器库。头文件公开的API应该与供应商无关......所有供应商头文件库都不包含在我的任何头文件中。

我的一个常见模式是通过仅使用指向某些" unknown"的指针,使供应商成员数据不透明。 vendor struct / class / typedef / pod type。

// myclass.h
class MyClass 
{
 ...
private:
   VendorThing* vendorData;
};

和实现(注意:每个实现都是特定于供应商的;都具有相同的* .h文件)

// myclass_for_vendor_X.cpp
#include "vendor.h"
... {
   vendorData->doSomething();
or
   VendorAPICall(vendorData,...);
or whatever

我遇到的问题是VendorThing可能有很多不同的东西。它可以是类,结构,类型或pod。我不知道,我也不想关心头文件。但是如果选错了,那么如果包含供应商头文件以及我的头文件,它就不会编译。例如,如果这是VendorThing"vendor.h"的实际声明:

typedef struct { int a; int b; } VendorThing;

然后,您不能将VendorThing转发为class VendorThing;。我根本不关心VendorThing的类型,我想要的只是将其视为void *的公共接口(即为指针分配空间,即它),以及实现用正确的指针类型来思考它。

我遇到的两个解决方案是" d-pointer"在Qt中找到的方法,通过替换VendorThing新结构VendorThingWrapper

来添加间接级别
// myclass.h
struct VendorThingWrapper;
class MyClass 
{
 ...
private:
   VendorThingWrapper* vendorDataWrapper;
};

并在你的cpp文件中

// myclass.cpp
#include "vendor.h"
struct VendorThingWrapper {
   VendorThing* vendorData;
};

... {
   vendorDataWrapper->vendorData->doSomething();
}

但是这增加了第二个指针取消引用,这不是一个大问题,但由于这是针对嵌入式系统,我不想仅仅因为语言不能做我想做的事情而增加这些开销

另一件事就是声明它无效

// myclass.h
class MyClass 
{
 ...
private:
   void* vendorDataUntyped;
};

并在实施中

//myclass.cpp
#include "vendor.h"
#define vendorData ((VendorThing*)vendorDataUntyped)

 ... {
   vendorData->doSomething();
}

但#define总是在我嘴里留下不好的味道。必须有更好的东西。

2 个答案:

答案 0 :(得分:1)

如果您愿意选择VendorThingWrapper的路径,那么您只需允许包装器包含数据本身,而不是指向它的指针。这为您提供了抽象层,避免了额外的取消引用。

// myclass.cpp
#include "vendor.h"
struct VendorThingWrapper {
   VendorThing vendorData;
};

... {
   vendorDataWrapper->vendorData.doSomething();
}

答案 1 :(得分:1)

您可以使用:

来避免额外的指针取消引用
#include "vendor.h"

struct VendorThingWrapper : public VendorThing {};

当然,在这一点上,使用名称MyClassData代替VendorThingWrapper更有意义。

MyClass.h:

struct MyClassData;

class MyClass
{
   public:

      MyClass();
      ~MyClass();

   private:
      MyClassData* myClassData;
};

MyClass.cpp:

struct MyClassData : public VendorThing {};

MyClass::MyClass() : myClassData(new MyClassData())
{
}

MyClass::~MyClass()
{
   delete myClassData;
}

<强>更新

我能够编译和构建以下程序。未命名的struct不是问题。

struct MyClassData;

class MyClass
{
   public:

      MyClass();
      ~MyClass();

   private:
      MyClassData* myClassData;
};


typedef struct { int a; int b; } VendorThing;

struct MyClassData : public VendorThing
{
};

MyClass::MyClass() : myClassData(new MyClassData())
{
   myClassData->a = 10;
   myClassData->b = 20;
}

MyClass::~MyClass()
{
   delete myClassData;
}

int main() {}