This question is somewhat related to this one, but not the same... please don't refer me to it...
In another question I asked (a different question) about a class similar to this one:
#include <memory>
#include <set>
using namespace std;
class Base : public enable_shared_from_this<Base>
{
public:
explicit Base(Base *parent = nullptr) : parent(parent) { parent->children.insert(shared_from_this()); }
private:
Base *parent; // weak pointer
set<shared_ptr<Base>> children;
};
Some of the responds mentioned (correctly) that I can't use shared_from_this()
in the constructor.
I read about this issue that the best solution (short of using boost::intrusive_ptr
) would be to use a static factory method instead of a constructor but my base class is actually virtual so my code turns out this way:
#include <memory>
#include <set>
using namespace std;
class Base : public enable_shared_from_this<Base>
{
protected:
Base() {};
void SetParent(Base *_parent)
{
parent = _parent;
parent->children.insert(shared_from_this());
}
private:
Base *parent = nullptr;
set<shared_ptr<Base>> children;
};
class Derived : public Base
{
public:
static Derived *Create(Base *parent = nullptr)
{
Derived *obj = new Derived();
if (parent) obj->SetParent(parent);
return obj;
}
private:
Derived() : Base() {};
};
However, this would force me to write boilerplate code for every child class, therefore the natural evolution would be to write it as a template factory at the base class, but since I want the derived class constructor to be private (to force using the static factory) I have to declare the base class as a friend in the derived class, resulting that the following code:
#include <memory>
#include <set>
using namespace std;
class Base : public enable_shared_from_this<Base>
{
public:
template<typename T> static T* Create(Base *parent = nullptr)
{
T *obj = new T();
if (parent) obj->SetParent(parent);
return obj;
}
protected:
Base() {};
void SetParent(Base *_parent)
{
parent = _parent;
parent->children.insert(shared_from_this());
}
private:
Base *parent = nullptr;
set<shared_ptr<Base>> children;
};
class Derived : public Base
{
private:
friend class Base;
Derived() : Base() {};
};
So my question is... is there a more elegant way to do this (preferably shorter and without boost and friend classes)...?