Я пытаюсь создать библиотеку 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_;
};
Проблема здесь в том, что (а) дескриптор должен сохранять ссылку на ресурс, и (б) ресурс должен иметь возможность привести дескриптор к пустоте *. К сожалению, это приводит к круговой зависимости.
Любые идеи о том, как реструктурировать этот?
ПРИМЕЧАНИЕ. Ответ заключается не в том, чтобы просто «включить xxx.hpp» или в предварительном объявлении одного из классов.
Это нужно как-то реструктурировать, я просто не могу понять, как это сделать.
Добавление class Handle
так как прямое объявление к началу файла ресурсов не работает, потому что (void *)
приведение является частью определения дескриптора, которое Resource все еще не видит. Аналогично, изменение актерского состава на void * ptr()
Функция-член приводит к той же проблеме.
Перемещение определений функций в файл .cpp также не является ответом — оно должно быть только заголовком.
Ну, это шаблоны на помощь (СНОВА!):
// 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_;
};
Не включайте файлы заголовков друг в друга, вместо этого у вас есть предварительная декларация классы. Таким образом, они могут быть использованы в качестве ссылок или указателей.
Итак, в 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*
Оператор Typecasting внутри do_something
функция, вы должны переместить эту реализацию в отдельный исходный файл. В этот исходный файл вы можете включить оба заголовочных файла, чтобы получить доступ ко всем функциям.