假设我正在编写一个静态库。让它有一个类 Foo
// mylib.h
#include <dependency_header_from_other_static_library.h>
class Foo {
// ...
private:
type_from_dependent_library x;
}
如您所见,这个库(我们称它为 mylib
)依赖于另一个库。它编译得很好。但是当用户编译它的代码(使用 Foo
并包含 mylib.h
)并与我的库链接时,编译失败,因为用户需要有 dependency_header_from_other_static_library.h
头文件来编译代码。
我想对用户隐藏这种依赖性。如何做到这一点?想到的一件事是 PIMPL
习语。喜欢:
// mylib.h
#include <dependency_header_from_other_static_library.h>
class Foo {
// ...
private:
class FooImpl;
boost::shared_ptr<FooImpl> impl_;
}
// mylib_priv.h
class FooImpl {
// ...
private:
type_from_dependent_library x;
}
但这需要我在FooImpl
中复制类Foo
的接口(interface)。而且,在我的案例中使用 PIMPL
是否有点矫枉过正?
谢谢。
最佳答案
将一个 header 与其他 header 分离时,您可以使用以下几种方法:
如果使用的库对它如何声明其类型作出 promise ,您可以在您的 header 中转发声明所需的类型。当然,这仍然意味着您只能将这些类型称为指针或在 header 中的函数签名中,但这可能已经足够了。例如,如果使用的库 promise 有一个
class LibraryType
你需要使用,你可以做这样的事情:// Foo.h class LibraryType; class Foo { // ... LibraryType* data; };
这可能会减少您使用该类型所需的时间,而无需包含其 header ,也无需跳过 PImpl 方法。
如果图书馆不 promise 其声明类型的方式,您可以使用
void*
以引用相应的类型。当然,这意味着无论何时访问实现中的数据,都需要强制转换void*
。到适当的类型。由于类型是静态已知的,因此使用static_cast<LibraryType*>
非常好,也就是说,不会因为转换而产生任何开销,但这样做仍然相对痛苦。当然,另一种选择是使用 PImpl 习惯用法。如果您的类型提供任何合理的服务,它可能会相当多地改变接口(interface),并且它不应该在类本身和私有(private)声明的类型之间复制接口(interface)。另外,请注意私有(private)类型只是一个数据容器,也就是说,将它设为
struct
是合理的。并且对其访问没有任何保护。唯一真正的问题是您需要确保类型的定义在调用析构函数的位置可见。使用std::shared_ptr<T>(new T(/*...*))
对此进行了安排。
实际上,所有这三种方法都做同样的事情,尽管技术略有不同:它们为您提供了一个不透明的句柄,用于头文件中,其定义只有实现知道。这样库的客户端就不需要包含相应的头文件了。但是,除非在构建库时解析符号,否则客户端仍然需要访问使用的库。
关于c++ - 向库用户隐藏库依赖项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13103311/