Library design: Hiding dependencies

2019-03-21 06:22发布

I'm attempting to build a library that uses a third-party library internally, but I do not want to expose and of this third-party library to the user of my library. This way, when the static library is built, the user will only need my header and the compiled library.

How do I deal with private members in my class definitions that are defined in the 3rd party library?

For example . .

header:

#include "ThirdPartyLib.h"
class DummyClass
{
    TypeFromThirdParty tftp;

public:
    bool checkStuff(const float) const;
};

implementation:

#include "ThirdPartyLib.h"
#include "dummy.h"    
bool DummyClass::checkStuff(const float t)
{
    return tftp.isOk(t);
}

The offending portion is the #include "ThirdPartyLib.h" in the header, as then the user of my library will need more than my library.

One way of getting around this might be to forward declare all third party types used in the header and then replace the value types with references, but I'm wondering if there is another method or design that I am completely overlooking?

1条回答
看我几分像从前
2楼-- · 2019-03-21 06:39

The "private implementation class" or "pimpl" idiom is one approach. This keeps all mention of the third-party library (and other implementation details) out of the header, at the cost of an extra level of indirection:

// header
#include <memory>

class DummyClass {
public:
    DummyClass();
    ~DummyClass();
    bool checkStuff(float t);

private:
    struct Impl;
    std::unique_ptr<Impl> impl;
};

// source
#include "DummyClass.h"
#include "ThirdPartyLib.h"

struct DummyClass::Impl {
    TypeFromThirdParty tftp;
};

DummyClass::DummyClass() : impl(new Impl) {}

// This must be defined here, since ~unique_ptr requires Impl to be complete
DummyClass::~DummyClass() {}

bool DummyClass::checkStuff(float t) {return impl->tftp.isOk(t);}

Another approach is to define an abstract interface, and a factory to create the concrete implementation class. Again, this removes all implementation details from the header, at the cost of an extra indirection:

// header
#include <memory>

struct DummyInterface {
    virtual ~DummyInterface() {}
    virtual bool checkStuff(float t) = 0;

    static std::unique_ptr<DummyInterface> create();
};

// source
#include "DummyClass.h"
#include "ThirdPartyLib.h"

struct DummyClass : DummyInterface {
    TypeFromThirdParty tftp;
    bool checkStuff(float t) {return tftp.isOk(t);}
};

std::unique_ptr<DummyInterface> DummyInterface::create() {
    return std::unique_ptr<DummyInterface>(new DummyClass);
}
查看更多
登录 后发表回答