在 C++ 对象包装器中安全地包含 C 代码



我有一个C库,它定义了一个类型,比如myCtype,以及一些使用myCtype类型变量的例程。我想将一个C++对象定义为单个myCtype变量的包装器。让我们假设包含myCtype定义的 C 标头是myCtype.h。具有标头mywrapper.hppmywrapper.cpp代码实现的C++代码如下所示

mywrapper.hpp

extern "C" {
#include "myCtype.h"
}
class mywrapper
{
myCtype v;
public:
//...
// Constructor and some methods here
// ...
}

mywrapper.cpp

#include "mywrapper.hpp"
// ...
// Constructor and methods of mywrapper here
// ...

这种方法的问题在于 C 标头myCtype.h可能包含几个"C 样式"宏、定义和内联函数,这些宏、定义和内联函数可能会与C++代码的其余部分发生冲突。 由于myCtype的定义,mywrapper.hpp需要包括myCtype.h。因此,每当我想使用mywrapper是一个C++代码时,我都需要包含mywrapper.hpp,这将不需要的myCtype.h汇集在一起。 即使myCtype.h的定义和内联函数与当前C++代码不冲突,也最好将它们隐藏在C++代码中。

请注意,我不需要myCtype成员mywrapper::v可见,因为我将其声明为私有。因此,出于所有目的,使用mywrapper的C++代码可以完全忽略myCtype.h的内容

这个问题的一个解决方案可能是使用void *指针来保存myCtype的实例,如下所示。

mywrapper.hpp

class mywrapper
{
void *v;
public:
mywrapper();
virtual ~mywrapper();
//...
// some methods here
// ...
}

mywrapper.cpp

#include "mywrapper.hpp"
#include <cstdlib>
extern "C" {
#include "myCtype.h"
}
mywrapper::mywrapper() : v(malloc(sizeof(myCtype)))
{
// Some initialization of v here
}
virtual mywrapper::~mywrapper()
{
free(v);
}
// ...
// Methods of mywrapper here
// ...

现在只有mywrapper.cpp的编译单元包含myCtype.h,而包含mywrapper.hpp的C++代码不会带来myCtype.h。 但是,此解决方案带有使用void *指针的类型不安全。

有没有更好的解决方案?它应该:

  • C 库包装在 C++ 对象包装器中
  • 将 C 标头myCtype.h"隐藏"在单独的编译单元中, 独立于使用包装器的C++代码
  • 确保无处不在的字体安全

将库代码隔离在单个编译单元中并用您自己的接口包装它实际上是一项非常常见的设计任务。显然,您的解决方案非常接近您想要的,除了 void 类型指针。

前向声明可以为您解决这个问题,但我认为myCtype是一个typedef?如果是这样,我会建议暂时打破隔离并查看库标头。假设myCtype定义如下:

typedef struct _myCtype {
// Members...
} myCtype

然后,C++标头可能如下所示:

class mywrapper
{
struct _myCtype *v;
// More members...
}

请注意它是如何工作的,mywrapper.hpp不需要包含myCtype.h标头,因为它是前向声明。但是在你的mywrapper.cpp中,如果你在顶部包含myCtype.h,则成员v将被视为一个适当的myCtype指针,而无需强制转换。

最新更新