0

我正在尝试围绕外部 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”或前向声明其中一个类。这需要以某种方式重组,我只是不太明白如何。

将 aclass Handle作为前向声明添加到 Resource 文件的顶部不起作用,因为强制转换(void *)是 Resource 仍然无法看到的 Handle 定义的一部分。同样,将强制转换更改为void * ptr()成员函数会导致相同的问题。

将函数定义移动到 .cpp 文件也不是答案——它必须是仅标题。

4

2 回答 2

4

好吧,这是救援的模板(再次!):

// 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_;
};
于 2013-01-15T14:00:35.043 回答
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,因此您必须将该实现移动到单独的源文件中。在该源文件中,您可以包含两个头文件,因此可以访问所有函数。

于 2013-01-08T14:26:47.577 回答