当全局函数需要指向 impl 的指针时,如何防止 impl 细节出现在头文件中?
How to prevent impl details from being in the header file when a global function needs a pointer to the impl?
我在我的代码中大量使用 pimpl idiom,主要是为了减少编译时间。
我遇到了调用 C 库的情况。我有一个 C++ 包装器 class,它有它的接口,血淋淋的细节都在 impl
中,当然:
class some_class {
public:
void some_init();
...
private:
class impl;
std::unique_ptr<impl> m_pimpl;
}
在 cpp 文件中,我必须在 C 库中注册一个回调函数,以便为它提供一个指针。我想将此函数调用转发给相应的成员函数。客户端(即此函数的用户)根本不需要知道这个细节:
static void from_c_func(void *ptr_to_class_impl) {
static_cast<some_class::impl *>(ptr_to_class_impl)->from_c_func();
}
void some_class::some_init() {
create_c_thing(static_cast<void *>(this->m_pimpl.get()), from_c_func);
}
问题是 some_class::impl
被声明为私有。我只能想到不完美的解决方案:
- 在头文件中制作
class impl;
public。这并不理想,因为它确实应该是 private
- 它恰好是一个非 class 函数需要看到它的实现细节。
- 将
from_c_func
放在头文件中,然后friend
。这并不理想,因为 some_class
的实现细节正在泄露。更改实现可能需要更改头文件,然后重新编译很多不需要重新编译的东西,这让我很不高兴。
- 给
from_c_func
一个指向some_class
本身的指针,然后在some_class
上调用一个函数。这将需要将该函数放入头文件中,这又是一个实现细节 - 无论如何非友元函数都必须 public
才能调用它。
怎么办?到目前为止,我最好的选择似乎是 #1,但有没有更好的方法?
您可以在 impl
中移动您的函数
static void some_class::impl::from_c_func(void *ptr_to_class_impl) {
static_cast<some_class::impl *>(ptr_to_class_impl)->from_c_func();
}
我在我的代码中大量使用 pimpl idiom,主要是为了减少编译时间。
我遇到了调用 C 库的情况。我有一个 C++ 包装器 class,它有它的接口,血淋淋的细节都在 impl
中,当然:
class some_class {
public:
void some_init();
...
private:
class impl;
std::unique_ptr<impl> m_pimpl;
}
在 cpp 文件中,我必须在 C 库中注册一个回调函数,以便为它提供一个指针。我想将此函数调用转发给相应的成员函数。客户端(即此函数的用户)根本不需要知道这个细节:
static void from_c_func(void *ptr_to_class_impl) {
static_cast<some_class::impl *>(ptr_to_class_impl)->from_c_func();
}
void some_class::some_init() {
create_c_thing(static_cast<void *>(this->m_pimpl.get()), from_c_func);
}
问题是 some_class::impl
被声明为私有。我只能想到不完美的解决方案:
- 在头文件中制作
class impl;
public。这并不理想,因为它确实应该是private
- 它恰好是一个非 class 函数需要看到它的实现细节。 - 将
from_c_func
放在头文件中,然后friend
。这并不理想,因为some_class
的实现细节正在泄露。更改实现可能需要更改头文件,然后重新编译很多不需要重新编译的东西,这让我很不高兴。 - 给
from_c_func
一个指向some_class
本身的指针,然后在some_class
上调用一个函数。这将需要将该函数放入头文件中,这又是一个实现细节 - 无论如何非友元函数都必须public
才能调用它。
怎么办?到目前为止,我最好的选择似乎是 #1,但有没有更好的方法?
您可以在 impl
static void some_class::impl::from_c_func(void *ptr_to_class_impl) {
static_cast<some_class::impl *>(ptr_to_class_impl)->from_c_func();
}