【问题标题】:Hiding library dependencies from library users对库用户隐藏库依赖项
【发布时间】:2012-10-17 16:28:14
【问题描述】:

假设我正在编写一个静态库。让它有一个类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 是不是有点矫枉过正?

谢谢。

【问题讨论】:

    标签: c++ dependencies static-libraries pimpl-idiom


    【解决方案1】:

    在将标头与其他标头分离时,您可以使用以下几种方法:

    1. 如果使用的库对如何声明其类型做出承诺,您可以在标头中转发声明所需的类型。当然,这仍然意味着您只能将这些类型称为指针或标头中的函数签名,但这可能已经足够了。例如,如果使用的库承诺有一个您需要使用的class LibraryType,您可以执行以下操作:

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

      这可能会减少您使用该类型而不包括其标题和跳过 PImpl 方法的必要时间。

    2. 如果库没有承诺如何声明它的类型,您可以使用void* 来引用相应的类型。当然,这意味着每当您在实现中访问数据时,您都需要将void* 强制转换为适当的类型。由于类型是静态已知的,因此使用 static_cast&lt;LibraryType*&gt; 非常好,即不会因强制转换而产生任何开销,但这样做仍然相对痛苦。

    3. 当然,另一种选择是使用 PImpl 习语。如果你的类型提供了任何合理的服务,它可能会改变接口相当多,它不应该在类本身和私有声明的类型之间复制接口。另外,请注意,私有类型只是一个数据容器,也就是说,将其设为 struct 并且对其访问没有任何保护是合理的。唯一真正的问题是您需要确保类型的定义在调用析构函数时可见。使用std::shared_ptr&lt;T&gt;(new T(/*...*)) 可以解决这个问题。

    实际上,所有三种方法都做同样的事情,尽管技术略有不同:它们为您提供了一个不透明的句柄,用于头文件中,其定义只有实现知道。这样库的客户端就不需要包含相应的头文件了。但是,除非在构建库时解析符号,否则客户端仍然需要访问使用的库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-05
      • 2020-12-03
      • 1970-01-01
      • 1970-01-01
      • 2020-10-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多