knivil
knivil

Reputation: 805

Exporting forward declared classes from a DLL

I want to export a class from a DLL. It uses the Pimpl idiom like:

#ifdef THING_EXPORT
#define THING_API __declspec(dllexport)
#else
#define THING_API __declspec(dllimport)
#endif

class thing_impl;

class THING_API thing
{
public:
    ...
private:
    thing_impl* pimpl_;
};

The constructor or destructor (or any method) of thing_impl will not be available outside of that DLL. Do I have to put THING_API in front of the forward declared name thing_impl?

Upvotes: 1

Views: 1168

Answers (1)

Niall
Niall

Reputation: 30606

Do I have to put THING_API in front of the forward declared name thing_impl?

It depends, but given the nature of the pimpl idiom, no you would not need to export it.

You could get warnings and errors about it not being exported, these can be silenced either for the entire project, or limit it to the scope of the member variable (as below);

class thing_impl;

class THING_API thing
{
public:
    ...
private:
    #pragma warning(push)
    #pragma warning(disable: 4251)
    thing_impl* pimpl_;
    #pragma warning(pop)
};

Other factors to consider in the implementation is to declare the "pimpl" implementation class thing_impl as private inside the main thing class to further limit potential access.

class THING_API thing
{
public:
    thing(const thing&);
    thing& operator=(const thing&);
    thing(thing&&); // if needed
    thing& operator=(thing&&); // if needed
    ~thing();
    ...
private:
    class thing_impl;
    #pragma warning(push)
    #pragma warning(disable: 4251)
    thing_impl* pimpl_;
    #pragma warning(pop)
};

One thing to note is that when exporting a class from a DLL, the entire class will be exported, so make sure that the appropriate copy constructors, copy assignment operators and destructors are there (as above) and implemented (additional the move ones if required). If they are not there, the compiler will generate them and they are more than likely not going to be correct given the use of the pimpl_ member. To this end you could also consider using a std::shared_ptr to assist in managing the pimpl_.

Upvotes: 1

Related Questions