Я проектирую иерархию объектов, в которой базовый класс всех объектов Node
, который, как ожидается, будет разделен на подклассы. Подклассы Node
будет содержать дочерние элементы, но тип дочернего элемента может варьироваться от одного подкласса к другому.
Я реализую право собственности на дочерние элементы путем частного наследования от Owner<>
класс, который является просто оберткой для std::vector
, Я хочу показать это владение базовому классу (но больше никому), потому что существует много повторений в отношении добавления и удаления дочерних элементов. Итак, я придумал это:
#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;
}
Этот подход выглядит немного грязно, потому что я храню ссылку на производный класс в базовом классе (я никогда раньше этого не видел). Это хорошая практика? Существуют ли более эффективные способы сохранения дочернего владения в производном классе при обработке общего обслуживания детей в базовом классе?
Вы почти там. Не храните ссылку на DERIVED_T
в Node
, Просто пиши:
auto derivedThis& = *static_cast<DERIVED_T*>(this);
в каждой из функций, которые нуждаются в этом. (Или же const DERIVED_T*
при необходимости).
Других решений пока нет …