0

I am about to write a C++ framework that will later be used by different C++ applications. The framework will provide one main class, which will be instantiated by the application. That main class will make use of some other classes within the framework. And there will be some helper classes, to be used directly by the application.

Now I am thinking of how I should encapsulate that class framework. I could write the header and source files as usual, and then include those in the applications that will make use of the framework, so that all will be compiled in one go together with the application.

But I am not sure whether this is "the best" approach in my case. Wouldn't it be an option to put the whole framework into a DLL and then link that DLL to the applications? However, I also read that it is often not the best idea to let a DLL export whole classes, and that this approach might lead to difficulties when using STL templates as data members.

Can you recommend an approach to me, maybe something else I have not mentiond above, incl. the pros and cons of all these options?

Community
  • 1
  • 1
Matthias
  • 9,817
  • 14
  • 66
  • 125
  • I don't have time for a detailed answer right now - but look into **static libraries** to see if that fits your requirement. – Allison Lock Nov 24 '16 at 14:42
  • Minimizing the amount of exposed implementation is always a good idea, especially so in C++. Use an interface or pimpl. If you cannot avoid exceptions or exposing standard C++ library template classes then there's no real point in trying to make it better, it is only ever going to work if the client app uses the exact same compiler version and build settings. – Hans Passant Nov 24 '16 at 14:52
  • @HansPassant Thanks, I think I understand what you mean, in theory at least. But what does this mean for my case? Client apps will use different compilers for sure, so do you mean that a DLL is not an option for me? – Matthias Nov 24 '16 at 15:09
  • 1
    You have lots of DLLs on your machine that were created by one company and used in the code of another. But they don't use a native C++ interface, there is no agreed ABI for C++. Common choices are a VM language, COM or a C-style interface. – Hans Passant Nov 24 '16 at 15:15

1 Answers1

1

You can create a C interface using opaque pointers, which is needed in your case because of the varying types and versions of compilers involved. Note that you may not accept or return non-C types, unless you also wrap them in opaque pointers. It's not hard, but there's a bit of work needed on your behalf.

Assuming a class 'YourClass', you would create a YourClassImpl.h and YourClassImpl.cpp (if needed) containing your C++ class code.

YourClassImpl.h

class YourClass
{
    private:
        int value = 12345;

    public:
        YourClass() {}
        ~YourClass() {}

        int getThing() { return value; }
        void setThing(int newValue) { v = newValue}
};

You would then create a YourClass.h which would be your C header file (to be included by the users of your DLL), containing an opaque pointer typedef and the declarations of your C-style interface.

YourClass.h

#ifdef MAKEDLL
#  define EXPORT __declspec(dllexport) __cdecl
#else
#  define EXPORT __declspec(dllimport) __cdecl
#endif

extern "C"
{
    typedef struct YourClass *YC_HANDLE;
    EXPORT YC_HANDLE CreateYourClass();
    EXPORT void DestroyYourClass(YC_HANDLE h);
    EXPORT int YourClassGetThing(YC_HANDLE h);
    EXPORT void YourClassSetThing(YC_HANDLE h, int v);
}

In YourClass.cpp you would define those functions.

YourClass.cpp

#include "YourClass.h"
#include "YourClassImpl.h"
extern "C"
{
    EXPORT YC_HANDLE CreateYourClass()
    {
        return new YourClass{};
    }

    EXPORT void DestroyYourClass(YC_HANDLE h)
    {
        delete h;
    }

    EXPORT int YourClassGetThing(YC_HANDLE h)
    {
        return h->getThing();
    }

    EXPORT void YourClassSetThing(YC_HANDLE h, int v)
    {
        h->setThing(v);
    }
}

In your users code they would include YourClass.h.

TheirCode.cpp

#include "YourClass.h"

int ResetValue(int newValue)
{
    YC_HANDLE h = CreateYourClass();
    auto v = YourClassGetThing(h);
    YourClassSetThing(h, newValue);
    DestroyYourClass(h);

    return v;
}

The most usual way of linking to your DLL would be with LoadLibrary/GetProcAddress - I'd also advise adding a .def file to your project to ensure that the functions are named 'nicely' and are not difficult to access because of any name decoration.

Some issues to keep an eye out for:

  1. Only the standard C fundamental types can be passed back and forth across the interface. Don't use any C++ specific types or classes.
  2. PODs and arrays of PODs may be safe for you to use, but watch out for any packing or alignment issues.
  3. Exceptions must not cross the interface boundaries - catch anything that gets thrown and convert it to a return code or equivalent.
  4. Ensure that memory allocated on either side of the boundary is deallocated on the same side.
IanM_Matrix1
  • 1,564
  • 10
  • 8
  • Thanks a lot for your detailed answer. By reading it I more and more come the to conclusion that a static library might be the better option my case. Would you agree? – Matthias Nov 28 '16 at 14:13
  • Most definitely, but that would require you to compile your DLL for each compiler type/version too. Best might be to give them the library in source code form so that they can compile it themselves. – IanM_Matrix1 Nov 28 '16 at 14:29