隐藏库用户的库依赖关系

Hiding library dependencies from library users

本文关键字:关系 依赖 用户 隐藏      更新时间:2023-10-16

考虑我正在写一个静态库。让它有一个Foo

// mylib.h
#include <dependency_header_from_other_static_library.h>
class Foo {
    // ...
private:
    type_from_dependent_library x;
}

您可以看到此库(让它称为mylib)取决于另一个库。它的编译很好。但是,当用户编译它的代码(使用Foo并包含mylib.h)并与我的lib链接时,汇编失败了,因为用户还需要将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类的接口。而且,在我的情况下使用PIMPL是过度的吗?

谢谢。

将标头与其他标头解耦时,您可能可以使用一些方法:

  1. 如果二手库对其声明其类型的方式有所保证,则您可能能够转发标题中所需的类型。当然,这仍然意味着您只能将这些类型称为标题中的指针或功能签名中,但这可能足够好。例如,如果二手库有望使用您需要使用的class LibraryType,则可以做类似的事情:

    // Foo.h
    class LibraryType;
    class Foo {
        // ...
        LibraryType* data;
    };
    

    这可能会削减您的必要松弛,以便在不包括标头的情况下使用该类型,而无需跳过Pimpl方法。

  2. 如果图书馆没有向其声明它的声明方式提出承诺,则可以使用void*参考相应类型。当然,这意味着,每当您访问实施中的数据时,都需要将void*投放到适当的类型。由于该类型在静态上是已知的,因此使用static_cast<LibraryType*>非常好,即,由于演员阵容而没有开销,但仍然相对痛苦。

  3. 另一种选择当然是使用pimpl习惯。如果您键入任何合理的服务,它可能会大大更改接口,并且复制类本身和私人声明类型之间的接口不应大。另外,请注意,私有类型只是一个数据容器,即合理地将其作为struct,并且对其访问没有保护。唯一真正的问题是,您需要确保在调用破坏者的点上可见类型的定义。使用std::shared_ptr<T>(new T(/*...*))为此安排。

有效地,所有三种方法都采用相同的操作,尽管技术略有不同:它们为您提供了一个不透明的手柄,该手柄可在标题文件中使用,其定义仅是实现的。这样,库的客户端就不需要包括相应的标头文件。但是,除非在构建库时解决符号,否则客户仍然需要访问二手库。