我假设您总是将相同类型的实例放入 void*。
在这种情况下,pImpl 时间:
struct foo_impl; // note, just a name
struct C_foo {
foo_impl *foo_obj; // can use pointers to undefined structs in both C and C++
};
现在你的大部分问题都消失了。 C 将foo_obj 视为一个不透明的指针。
在 C++ 中,我们包含另一个头文件(示例字段):
// in C++ **only** header file -- C does not see this:
struct foo_impl {
int x;
std::vector<double> v;
foo_impl( int, double const* b, double const* e ); // constructor
};
// functions exposed to C, but implemented in C++ with visibility of the above foo_impl
extern "C" struct C_foo* alloc(int x, double const* b, double const* e) {
struct C_foo *out = new struct C_foo;
out->foo_obj = new foo_impl(x, b, e);
return out;
};
extern "C" void dealloc(struct C_foo *obj) {
delete obj->foo_obj;
delete obj;
}
你赢了。
请注意,struct 只是 C++ 中 class 的名称,默认为 public,而不是默认的 private。
我将名称从foo 更改为foo_impl,并在其中创建了一些示例数据。
如果您可以在void* 中添加多种不同的类型,我首先建议您使用虚拟析构函数放置一个纯虚拟接口类,并基本上遵循上述步骤。
现在,在某些情况下,您实际上希望在不透明指针中存储多个不同的、不相关的类型。这些并不常见。但在这些情况下,我们需要存储一个销毁函数。
同样,我更喜欢我上面的方法,但如果它不起作用,我们有这个。
deleter函数有几种存储方式:
typedef void(*foo_deleter)(void*);
struct C_foo {
void* foo_obj;
foo_deleter* deleter;
};
另一种方法是:
struct foo_impl;
struct C_foo {
foo_impl* foo_obj;
};
// elsewhere:
typedef void(*foo_deleter)(foo_impl*);
struct foo_impl {
foo_deleter* deleter;
};
template<typename T>
struct foo_details {
foo_impl header;
T* data;
~foo_details() { delete data; }
foo_details( T* in ):data(in) {}
foo_details( foo_details const& ) = delete;
foo_details& operator=( foo_details const& ) = delete;
foo_details():data(nullptr) { header.deleter=nullptr; }
};
然后分配一个foo_details 到foo_obj 存储一个foo,reinterpret_cast 到一个foo_impl(在标准布局条款下有效),并存储到foo_obj。
然后deleter 会将foo_impl、reinterpret_cast 转换为foo_details<foo> 和delete。
要访问数据,您必须弄清楚它是什么类型(您可以在foo_impl 中粘贴额外的类型信息,例如整数或其他),然后将reinterpret_cast 粘贴到适当的foo_details<?> 和访问其中的data。
意识到您需要能够以某种方式提取不透明指针的类型信息才能使用它:考虑使用您在那里使用的任何机制来确定如何删除它。