隐藏库用户的库依赖关系 [英] Hiding library dependencies from library users

查看:87
本文介绍了隐藏库用户的库依赖关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一下,我正在编写一个静态库。使其具有类 Foo

Consider I'm writting a static library. Let it has a class 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 头文件来编译代码。

As you can see this library (let call it mylib) depends on another library. It compiles well. But when user compile it's code (that uses Foo and includes mylib.h) and linking with my lib the compilation fails, because user need to have dependency_header_from_other_static_library.h header file to compile code as well.

我想向用户隐藏此依赖项。如何做到这一点?想到的一件事是 PIMPL 习惯用法。像这样:

I want to hide this dependency from the user. How this can be done? The one thing that comes to mind is a PIMPL idiom. Like:

// 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 是否过大?

But it requires me to duplicate the interface of the class Foo in FooImpl. And, is it an overkill to use PIMPL in my case?

谢谢。

推荐答案

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

When decoupling a header from other headers, there are a few approaches you might be able to use:


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

  1. If the used library makes a promise about how it declares its types, you may be able to forward declare the needed types in your header. Of course, this still means you can only refer to these types as pointers or in function signatures in the header but this may be good enough. For example, if the used library promises to have a class LibraryType that you need to use, you can do something like this:

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

这可能会减少使用该类型所需的松弛时间,而无需包含其标题并且无需跳过PImpl

This may cut you the necessary slack to use the type without including its header and without jumping through a PImpl approach.

如果该库未对如何声明其类型做出保证,则可以使用 void * 来引用相应的类型。当然,这意味着只要您在实现中访问数据,就需要将 void * 转换为适当的类型。由于类型是静态已知的,因此使用 static_cast< LibraryType *> 是完全可以的,即,由于强制转换没有任何开销,但仍然相对麻烦

If the library doesn't make a promise about how it declares it types you may use void* to refer to the corresponding types. Of course, this means that whenever you access the data in your implementation, you'll need to cast the void* to the appropriate type. Since the type is statically known, using static_cast<LibraryType*> is perfectly fine, i.e., there isn't any overhead due to the cast, but it is still relatively painful to do.

当然,另一种选择是使用PImpl习惯用法。如果您键入内容提供任何合理的服务,则它可能会相当多地更改接口,并且在复制类本身与私有声明的类型之间的接口上应该不会有太大的作用。另外,请注意,私有类型只是一个数据容器,也就是说,合理地使它成为 struct 并且对其访问没有任何保护。唯一的实际问题是,您需要确保在调用析构函数的那一刻,该类型的定义是可见的。使用 std :: shared_ptr< T>(新的T(/*...*))进行安排。

The other alternative is, of course, to use the PImpl idiom. If you type provides any reasonably service, it will probably change the interface quite a bit and it shouldn't amount much to replicating the interface between the class itself and the privately declared type. Also, note that the private type is just a data container, i.e., it is reasonably to just make it a struct and have no protection to its accesses. The only real issue is that you need to make sure that the type's definition is visible at the point where the destructor is called. Using std::shared_ptr<T>(new T(/*...*)) arranges for this.

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

Effectively, all three approaches do the same thing although with slightly different techniques: they provide you an opaque handle to be used in the header file whose definition is only known to the implementation. This way, the client of the library doesn't need to include the corresponding header files. However, unless the symbols are resolved when building the library, it would still be necessary for the client to have access to the used library.

这篇关于隐藏库用户的库依赖关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆