I am designing an object hierarchy in which the base class of all objects is Node
, which is expected to be subclassed. Subclasses of Node
will contain child items, but the type of child can vary from one subclass to another.
I am implementing ownership of child items by privately inheriting from the Owner<>
class, which is just a wrapper for std::vector
. I want to expose this ownership to the base class (but nobody else), because there is a lot of repetition with regard to adding and removing child items. So I have come up with this:
#include <vector>
using namespace std;
//Class to contain child items
template <typename T>
struct Owner {
vector<T> children;
};
//Types of children that can be owned by nodes in the hierarchy
struct ChildType1{};
struct ChildType2{};
struct ChildType3{};
//Node base class
template <typename DERIVED_T>
struct Node {
Node(DERIVED_T& _derivedThis):
derivedThis(_derivedThis)
{}
template <typename ITEM_T>
void AddItem() {
/*Possibly do a lot of pre-checks here before adding a child*/
derivedThis.Owner<ITEM_T>::children.emplace_back();
}
//Reference to the most-derived subclass instance
DERIVED_T& derivedThis;
};
//A possible subclass of Node
struct DerivedNode:
private Owner<ChildType1>,
private Owner<ChildType2>,
public Node<DerivedNode>
{
friend struct Node<DerivedNode>;
DerivedNode():
Node(*this)
{}
};
int main() {
DerivedNode d;
d.AddItem<ChildType1>();
d.AddItem<ChildType2>();
//d.AddItem<ChildType3>(); //Fails to compile (intended behavior; DerivedNode should not own ChildType3 objects)
return 0;
}
This approach feels a bit messy because I'm storing a reference to a derived class in the base class (I have never seen this before). Is this good practice? Are there better ways of keeping child ownership in the derived class while handling generic child maintenance in the base class?
You are almost there. Don't store a reference to DERIVED_T
in Node
. Just write:
auto derivedThis& = *static_cast<DERIVED_T*>(this);
in each of the functions that need it. (Or const DERIVED_T*
as appropriate).