Search code examples
c++dllshared-librariesdllexport

C++ dynamic library with public api that obscures dependent libraries


I am trying to create a multi-platform library in C++ for use by C++ consumer applications. Call my library A. I want to ship a dynamic library file per target platform, and a header file (call this export.h) that the consumer app could use to compile and execute. My library depends on a third-party open-source library, written in c, which is difficult to link to correctly; call this library B.

In order to save my consumers the pains of linking to B, I want to abstract every call to it so that the consumer need not even have a single header file from B. Consumer app (C) should be able to compile with only A.dll, B.dll and export.h; and run with only A.dll and B.dll as dependencies (substituting the platform-specific suffix for a shared library as needed).

B defines a great many types, mostly structs. (B is not written in objective c, although it probably should have been.) Part of A's job is to produce classes that contain and manage groups of structs around logical lines, which are readily apparent. C needs to call functions belonging to classes in A, so the function prototypes need to be in export.h, but the B types cannot be in export.h or else C will need to include headers from B.

Is there a syntax that lets me define the public members of a class (in A) without also defining all the private members?

Obviously, there are no public members in A that rely on types from B. The closest thing I've found so far is this question. Opaque pointers may be part of the solution, but C needs access to functions of classes in A. I really don't want to write a helper function for every public A class member, though that would probably work. Any ideas?

Edit: As requested, explanation code.

Worker.h:

#include <SomeThirdPartyLib.h>
class Worker {
public:
  Worker();
  ~Worker();
  void DoWork();
private:
  Truck t;
}

SomeThirdPartyLib.h:

typedef struct TruckS {
  char data[200];
  char* location;
} Truck;

Worker.cpp:

#include "worker.h"
Worker::Worker() {}
Worker::~Worker() {}
Worker::DoWork() {
  t.location = "Work";
}

main.cpp:

#include <export.h>
int main(int argc, char** argv) {
  Worker w();
  w.DoWork();
}

Now I'm looking for the syntax to put in export.h that would allow this external application to be compiled using that header and my dll, but without requiring access to SomeThirdPartyLib.h.


Solution

  • Here is a technique that may be close to what you want to achieve.

    You can define an interface that relies only on public interfaces from A, and therefore lacks any dependency on B. The interface class includes a factory. This interface would be part of the header file for your library.

    class Interface {
    public:
    
        virtual void foo () = 0;
        virtual void bar () = 0;
    
        static std::unique_ptr<Interface> make ();
    
        virtual ~Interface () = default;
    };
    

    In a source file of your library, you would include header files for both A and B, and create an implementation of the interface as well as a definition of the factory.

    class Implementation : public Interface {
        //...
    };
    
    std::unique_ptr<Interface>
    Interface::make () {
        return std::make_unique<Implementation>();
    }
    

    So, users of your library get access to the interface, and can call the public methods without any knowledge of private members or private methods.

    Try it online!