Hiding library dependencies from library users

I think that I am writing a static library. Let it have class Foo

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

As you can see this library (let it be called mylib ) depends on another library. It compiles well. But when the user compiles his code (which uses Foo and includes mylib.h ) and links to my library, compilation fails because the user needs to have the dependency_header_from_other_static_library.h header file to compile the code.

I want to hide this dependency on the user. How can I do that? The only thing that comes to mind is the PIMPL idiom. How:

 // 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; } 

But this requires that I duplicate the interface of the Foo class in FooImpl . And, do I use PIMPL in excess?

Thanks.

+4
source share
1 answer

When untying a header from other headers, there are several approaches you could use:

  • If the library you are using makes a promise about how it declares its types, you can redirect the declaration of the necessary types to your header. Of course, this all the same means that you can only refer to these types as pointers or function signatures in the header, but this can be quite good. For example, if the promises library you are using has a class LibraryType that you should use, you can do something like this:

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

    This may make it necessary to use this type without using its header and without going through the PImpl approach.

  • If the library does not promise how it declares its types, you can use void* to indicate the corresponding types. Of course, this means that whenever you access data in your implementation, you need to point void* to the appropriate type. Since the type is statically known, using static_cast<LibraryType*> excellent, i.e. There is no overhead due to the cast, but it is still relatively painful.

  • Another alternative, of course, is to use the PImpl idiom. If you introduce any reasonable service, it will probably change the interface a bit, and it should not greatly affect the replication of the interface between the class itself and the private declared type. Also note that the private type is just a data container, i.e. It makes sense to just make it struct and not have protection against its access. The only real problem is that you need to make sure that the type definition is visible at the call point of the destructor. To do this, use std::shared_ptr<T>(new T(/*...*)) .

Effectively, all three approaches do the same thing, but with slightly different methods: they provide you with an opaque handle that will be used in the header file, the definition of which is known only for implementation. Thus, the library client does not need to include the corresponding header files. However, if characters are not allowed when creating the library, it is still necessary that the client has access to the library used.

+6
source

Source: https://habr.com/ru/post/1442527/


All Articles