如何在给定的自引用模板实现中摆脱抽象类?
我只是尝试实现跳过列表数据结构。 所以我想创建模板Node,以便我可以为不同的节点类实例化下一个链接的类,以避免类转换。 找到了这些问题:
Self-referencing Template in Template Argument
How to properly declare a self-referencing template type?
但他们都没有解决方案。然后我根据两行继承制作了自己的解决方案。一个是“抽象”模板的序列(用于Next参数传播)。另一种是实例化具体类。但感觉可以改进处理相同而没有冗余的抽象模板(NodeAbstract,NodeWithKeyAbstract等)。经过几次尝试后,我想请你帮助我:
template <class Value, class Next >
class NodeAbstract
{
public:
Value m_value;
Next * next;
NodeAbstract () : next(0) {}
Next * getNext() {return next;}
};
template <class Value, class Key, class Next >
class NodeWithKeyAbstract : public NodeAbstract <Value, Next >
{
public:
Key m_key;
};
template <class Value, class Key>
class NodeWithKey : public NodeWithKeyAbstract <Value, Key, NodeWithKey<Value,Key> >
{
};
template <class Value, class Key, int maxlevel, class Next>
class NodeSkipListAbstract : public NodeWithKeyAbstract<Value, Key, Next >
{
public:
Next * nextjump[maxlevel-1];
};
template <class Value, class Key, int maxlevel>
class NodeSkipList : public NodeSkipListAbstract<Value, Key, maxlevel, NodeSkipList<Value, Key, maxlevel> >
{
};
答案 0 :(得分:1)
如果我理解正确,你的问题基本上是不同的maxlevel
值会产生不同的类,所以你不能使用一个数组来存储它们(如果我和#39;我错了。)
你不能完全摆脱抽象类 - 如果你想让不同最高级别的节点作为不同的类(不同的模板特化),你必须为它们提供一些共同点。
好消息是你可以摆脱奇怪的重复模板模式 - 因为你使用指针你不必参考确切的实现类型(例如,知道确切的模板专业化)如果你的抽象给出了您可以访问所需的所有信息。您的代码也可以简化一点。
考虑以下代码:
template <class Key, class Value>
class Node {
public:
virtual ~Node() = default;
virtual std::size_t MaxLevel() const = 0;
virtual Node* Skip(size_t level) const = 0;
// add setter as well
Key key;
Value value;
};
template <class Key, class Value, std::size_t max_level>
class NodeImpl : public Node<Key, Value> {
public:
typedef Node<Key, Value> node_type;
NodeImpl() : skips() {}
size_t MaxLevel() const { return max_level; }
node_type* Skip(std::size_t level) const {
return level < max_level ? skips[level] : nullptr;
}
// add setter as well
private:
node_type* skips[max_level];
};
template <class Key, class Value>
class SkipList {
public:
typedef Node<Key, Value> node_type;
node_type* head;
};
这里Node
为你提供了跳过&#34;跳过&#34;行为。 NodeImpl
将用于生成具有不同最高级别的Node
,但最终使用的实现对您来说是透明的 - 您只能使用Node
的界面。同样在语法级别上,您只使用Node*
类型,因此各种实现都不会成为问题。虚析构函数将确保delete
释放所有内存,key
和value
始终可以作为公共字段访问。
这个代码当然可以改进。原始数组可以由std::array
替换。如果您决定使用max_level
并在构造函数中设置大小而不是数组(那么您只有std::vector
和{Node
,那么SkipList
作为模板的整体想法可以摆脱{1}})。作为奖励创建新节点会更容易,因为现在您必须编写一些工厂,其中所有NodeImpl
的特化都是从1到某个值。另外,指针可以被一些智能指针替换,以避免内存泄漏。