0

OpenVPN is a giant header only 'library'. I created a library based on it, which consists of a MyClass.h file that has a class MyClass that uses the headers from OpenVPN. I compile this library as libmy.

The problem is that when I try to use libmy in another project, I'm forced to include MyClass.h, which in turn includes all of the OpenVPN headers. I don't need them, since MyClass hides all OpenVPN-related things. However, since OpenVPN headers have some static variables like static int context_data_index (defined AND declared in header, here), these variables get duplicate definitions when I try to compile my new project.

Let me explain the problem better. This is MyClass.h:

class MyClass {
public:
//lots of 'methods' that hide OpenVPN-related things. Users of these methods dont even know about OpenVPN


private:
//Users of MyClass do not need to know about this unique_ptr, but I'm forced to show it in `MyClass.h`, which is why I get duplicated definitions
#ifndef DO_NOT_INCLUDE_OPENVPN_HEADERS
        std::unique_ptr<OpenVPNClient> openVpnClient;
#endif
}

as you can see, the users of MyClass don't have to know anything about OpenVPN objects. I even tried to put an #ifndef clause that conditionally includes std::unique_ptr<OpenVPNClient> openVpnClient; when compiling libmy but does not include when compiling the library that uses libmy, but I got terrible undefined behaviour by doing that. I guess it's because a class must have the same number of objects with the same objects in both the libmy implementation and in my new library.

What can I do about this problem?

Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150
  • 1
    One solution to hiding the implementation detail is to use PIMPL. [https://en.cppreference.com/w/cpp/language/pimpl](https://en.cppreference.com/w/cpp/language/pimpl) – drescherjm Jul 28 '20 at 11:33
  • ***I guess it's because a class must have the same number of objects with the same objects in both the libmy implementation and in my new library.*** You can't have 2 different declarations of the class. – drescherjm Jul 28 '20 at 11:36
  • 2
    You may be able to forward declare `OpenVPNClient`. The users of your class need not include the header. For this to work your destructor for `MyClass` needs to be defined in your translation unit. Related: [https://stackoverflow.com/questions/6012157/is-stdunique-ptrt-required-to-know-the-full-definition-of-t](https://stackoverflow.com/questions/6012157/is-stdunique-ptrt-required-to-know-the-full-definition-of-t) – drescherjm Jul 28 '20 at 11:39
  • @drescherjm Can you make this an answer? – yugr Jul 28 '20 at 11:45

2 Answers2

0

One solution to not requiring the users of your class to directly include the OpenVPN headers is to forward declare OpenVPNClient in your header for MyClass like this:

class OpenVPNClient;

For this to work your destructor for MyClass needs to be defined in your translation unit. This could be as simple as adding the following line to your source file for MyClass:

MyClass::~MyClass() = default;

There is more info on how to do this and why it is needed here:

Is std::unique_ptr<T> required to know the full definition of T?

An alternate solution is to use PIMPL with your class and completely hide the OpenVPNClient from the header. There is information on how to use PIMPL here:

https://en.cppreference.com/w/cpp/language/pimpl

In your question you asked about a solution where you used an #ifdef to hide the usage of the OpenVPNClient to users of your class but define it when building your class: I guess it's because a class must have the same number of objects with the same objects in both the libmy implementation and in my new library. You can't have 2 different definitions of the class. This will cause undefined behavior.

drescherjm
  • 10,365
  • 5
  • 44
  • 64
  • I am trying to find a better explanation for the last part but I am having a difficulty finding a duplicate. – drescherjm Jul 28 '20 at 12:00
0

Try

namespace my_namespace
{
   #include "something.h"
}