Given an abstract interface and an implementation derived from that interface, where constructors are protected (creation of these objects only being available from a class factory - to implement a DI pattern), how can I make use of make_shared in the factory function?
For example:
class IInterface
{
public:
virtual void Method() = 0;
};
class InterfaceImpl : public IInterface
{
public:
virtual void Method() {}
protected:
InterfaceImpl() {}
};
std::shared_ptr<IInterface> Create()
{
std::shared_ptr<IInterface> object = std:: make_shared<InterfaceImpl>();
return object;
}
make_shared obviously cannot access the protected constructor in InterfaceImpl, or indeed in IInterface, giving me the following error
error C2248: 'InterfaceImpl::InterfaceImpl' : cannot access protected member declared in class 'InterfaceImpl'
So reading here (question: How to make boost::make_shared a friend of my class), I tried putting the following into the implementation class:
friend std::shared_ptr<InterfaceImpl> std::make_shared<InterfaceImpl>();
It still wouldn't compile. So then I put another one into the IInterface class too. Still no joy. What have I done wrong here?
EDIT: Full source file used to compile, with "friend"...
#include <memory>
class IInterface
{
public:
friend std::shared_ptr<IInterface> Create();
virtual void Method() = 0;
};
class InterfaceImpl : public IInterface
{
public:
virtual void Method() {}
protected:
friend std::shared_ptr<IInterface> Create();
InterfaceImpl() {}
};
std::shared_ptr<IInterface> Create()
{
std::shared_ptr<IInterface> object = std::make_shared<InterfaceImpl>();
return object;
}
void main()
{
std::shared_ptr<IInterface> i = Create();
}
With VC10 the solution you linked to doesn't work - the construction of the instance of InterfaceImpl
doesn't happen in make_shared
, but in an internal type in std::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void)
.
I'd just make the Create()
function a friend
in your case and not use make_shared()
:
class InterfaceImpl : public IInterface {
// ...
protected:
friend std::shared_ptr<IInterface> Create();
InterfaceImpl() {}
};
std::shared_ptr<IInterface> Create() {
return std::shared_ptr<IInterface>(new InterfaceImpl());
}
... or use a custom make_shared()
implementation that you actually can befriend without relying on ugly implementation details.
An alternative would be to use something like this pass-key-idiom:
class InterfaceImpl : public IInterface {
public:
class Key {
friend std::shared_ptr<IInterface> Create();
Key() {}
};
InterfaceImpl(const Key&) {}
};
std::shared_ptr<IInterface> Create() {
std::shared_ptr<IInterface> object =
std::make_shared<InterfaceImpl>(InterfaceImpl::Key());
return object;
}