我正在尝试围绕外部C API创建一个仅限标头的C ++库。
C API使用void *
指针作为句柄。
这是个主意:
// resource.hpp
class Resource {
public:
// RAII constructor, destructor, etc.
// ...
void do_something(const Handle & h) {
do_something_impl( (void *) h);
}
};
// handle.hpp
class Handle
{
public:
Handle(size_t n, const Resource & res)
: p_(res.allocate(n)), res_(res) {}
// cast operation
operator void *() const { return p_; }
private:
void * p_;
Resource & res_;
};
这里的问题是(a)Handle必须保持对Resource的引用,以及(b)Resource需要能够将Handle转换为void *。不幸的是,这导致了循环依赖。
关于如何重组的任何想法?
注意:答案不是简单地“包含xxx.hpp”或转发声明其中一个类。 这需要以某种方式重组,我只是不知道如何。
将class Handle
作为前向声明添加到资源文件的顶部不起作用,因为(void *)
强制转换是资源仍无法看到的句柄定义的一部分。同样,将强制转换更改为void * ptr()
成员函数会导致同样的问题。
将函数定义移动到.cpp文件也不是答案 - 它只需要是标题。
答案 0 :(得分:3)
嗯,这是拯救的模板(再次!):
// resource.hpp
class Resource;
template<typename TResource> class Handle;
class Resource {
public:
// RAII constructor, destructor, etc.
// ...
void do_something(const Handle<Resource> & h) {
do_something_impl( (void *) h);
}
};
// handle.hpp
template<class TResource>
class Handle {
public:
Handle(size_t n, const TResource & res)
: p_(res.allocate(n)), res_(res) {}
// cast operation
operator void *() const { return p_; }
private:
void * p_;
TResource & res_;
};
答案 1 :(得分:1)
不要将头文件相互包含在一起,而是要有一个前向声明类。这样它们就可以用作引用或指针。
所以在resource.hpp中:
class Handle;
class Resource {
public:
// RAII constructor, destructor, etc.
// ...
void do_something(const Handle & h) {
do_something_impl( (void *) h);
}
};
在handle.hpp中:
class Resource;
class Handle
{
public:
Handle(size_t n, const Resource & res)
: p_(res.allocate(n)), res_(res) {}
// cast operation
operator void *() const { return p_; }
private:
void * p_;
Resource & res_;
};
由于您在void*
函数中使用do_something
类型转换操作符,因此必须将该实现移动到单独的源文件中。在该源文件中,您可以包含两个头文件,因此可以访问所有功能。