替代虚拟typedef而不使用模板

时间:2017-03-11 19:14:32

标签: c++ templates inheritance iterator

编辑更短的问题: 当使用指向抽象类的指针时,如何调用它指向的对象的实际类型的方法?

我有一个带有公共

的抽象BaseTree课程
virtual BaseTree const& operator[](NodeIndex const& poss) const = 0;

NodeIndex实际上std::vector<unsigned int>。我还有一个TreeBasicIterator类,其中包括

public:
    /// Access the tree to which m_tree points
    BaseTree& operator*() const
    {
        //checking...
        return (*m_tree)[*this];
    }

private:
    /// the tree the current iterator refers to
    BaseTree* m_tree=nullptr;

问题(我认为这是我最初问题的症结所在):

如何使用与* m_tree的实际类型对应的类的方法?现在,在解除引用我的迭代器时,我只能使用抽象类BaseTree的方法。

我希望避免将TreeBasicIterator作为模板(请参阅下面的初始问题)。

初步问题

对于C ++的许多(相对较新的?)用户,我想写

virtual typedef something my_virtual_type;

内部类定义。不幸的是,这是不可能的......

最受欢迎的替代方案似乎是模板,例如在alternative to virtual typedef中提供了很好的总结。

但是我不确定它是否涵盖了虚拟typedef的所有内容。我在下面提出了一个问题,我希望有一个虚拟的typedef。我有一个(临时?)工作解决方案使用重载而不是模板。

我想创建一个奇特的树结构,包括迭代器。

1)我定义了NodeIndex类型,我未来迭代器的祖先。 (NodeIndex在我的案例中std::vector<unsigned int>,但这并不重要。)

2)我定义了一个抽象的BaseTree类,在我的迭代器中使用。该类特别包括返回NodeIndex索引以在树中移动的虚拟方法(例如NodeIndex begin())和operator[](NodeIndex const&)

3)我定义了一个TreeBasicIterator类,继承自NodeIndex,为了一致性目的,包括对BaseTree的const引用,并实现各种迭代器方法(利用虚拟BaseTree)提供的方法。

(我实际上有两个类:TreeBasicIteratorConst_TreeBasicIterator,带有对const BaseTree的const引用;我使用预处理器宏来模仿基于const的模板,但是这个是另一个问题。)

4)我已经定义了一个TreeNode<T>模板类(T是节点内容),继承自BaseTree。目前,其begin()方法返回NodeIndex,其operator[]NodeIndex为参数,一切正常。

5)但是我想在我的TreeBasicIterator课程中加入TreeNode。我想加入一个

virtual typedef NodeIndex Iterator;

在我的BaseTree课程中,将虚拟begin()方法签名修改为Iterator begin()。 然后TreeNode将包含

virtual typedef TreeBasicIterator Iterator;

begin()方法签名为Iterator begin(), 一切都会好起来的。)

6)我不想在TreeBasicIterator上使用模板:它现在已经编译了一次。

使BaseTree成为一个模板会使TreeBasicIterator成为一个模板,因此BaseTree中的抽象的一部分优势就会失去。

BaseTree NodeIndex Iterator作为TreeNode类型进行实例化将是多余的:实际上,没有人会从该特定实例继承。

7)前瞻性:

我将使用具有固定或很少修改结构的树,但更频繁地修改节点内容,甚至更频繁地读取访问。为了优化访问权限,我打算进一步从TreeVector std::vector类派生,其中包括NodeIndex BasicTreeIterator(或Iterator?)索引的排序详尽TreeVectorTreeNode中的typedef虚拟类型将是std :: iterator。

8)当前(临时?)部分工作解决方案:

Iterator定义(通常是TreeBasicIteratorIterator类型(我的BaseTree类)。它不会覆盖BaseTree中的NodeIndex begin() const类型,但它可以。

TreeNode有一个Iterator begin() const方法,该方法既未被隐藏,又被NodeIndex next_index(NodeIndex) const方法BaseTree重载。它没有被覆盖。

同样地,我在TreeNode中有一个Iterator next_index(Iterator) const,它都是非隐藏的,并且{{1}}方法通过{{1}}方法重载。

1 个答案:

答案 0 :(得分:0)

所以,似乎没有人感兴趣......无论如何,这里是我的工作解决方案:混合模板和非模板类。

TreeBasicIterator仍然是非模板类,如问题中所述。

dynamic_cast是在BaseTree指针上调用树类特定方法的工具。但是,每次在代码中取消引用迭代器时都不必使用它。

我派生了一个模板TreeIterator类:

template<class MyTree> class TreeIterator: public TreeBasicIterator

其方法使用dynamic_cast,例如:

TreeIterator(BaseTree & tree): TreeBasicIterator(tree) {check_type();};

MyTree& operator*() const
{
    return dynamic_cast<MyTree &>(TreeBasicIterator::operator*());
}

void check_type()
{
    try
    {
        // uses the built-in checkings of dynamic_cast
        if(m_tree!=nullptr) dynamic_cast<MyTree &>(*m_tree);
    }
    catch(std::exception &e)
    {
        m_tree=nullptr; // invalidates the iterator
        throw e;
    }
}

当所做的事情与所使用的真实树类无关时,调用TreeBasicIterator的一劳永逸编译方法。