我正在尝试实现a-b树,作为从通用树派生的类。
通用树节点如下:
template<typename T>
struct TreeNode
{
T value;
std::vector<TreeNode*> children;
//Some other trivial stuff
};
a-b节点的结构如下:template<typename T>
struct ABTreeNode : TreeNode<T>
{
std::vector<T> keys;
//The idea is to omit the T value field of the base node and use that vector for the keys
};
同样在通用树类中存在一个根字段TreeNode *root;
而a-b构造函数是template<Typename T>
ABTree<T>::ABTree(T value)
{
GenericTree<T>::root = new ABTreeNode;
root->keys.push_back(value);
}
现在,通过这种方式,我需要在许多a-b树方法中使用向下转换,例如:template<typename T>
bool ABTree<T>::search(T value)
{
ABTreeNode *node = GenericTree<T>::root;
//....
}//Downcast base to derived
据我所知,向下铸造是一种不好的做法,并表示设计不良。我使用在派生结构中定义的变量但将节点声明为基本结构的事实似乎很容易出错。如果该节点被创建为基础节点而不派生会怎样?例如:
//Somewhere:
TreeNode *node = new TreeNode;//Instead of new ABTreeNode
//..
//Somewhere else
node->keys//Shouldn't that be an error?
我的方法正确吗?如果不是,我应该如何构造更好的结构?PS:请保留原始指针。
最佳答案
通过继承共享代码是一个错误的设计。更好的方法是使用Composition-请参见https://en.wikipedia.org/wiki/Composition_over_inheritance
为了在各种树的不同实现之间共享代码,我将公共(public)字段提取到一个结构中。
template <class T, class ChildT>
struct TreeNodeCommons
{
T nodeValue;
std::vector<ChildT*> children;
// more common fields
}
然后,将其附加到不同类型的节点上。template<typename T>
struct ABTreeNode
{
TreeNodeCommons<T, ABTreeNode<T>> commons;
std::vector<T> keys;
};
然后,您可以假设Node包含名为commons的字段来编写模板化算法,也可以编写Node特定算法。而且没有dynamic_casts。