【问题标题】:alternative to virtual typedef without templates替代没有模板的虚拟类型定义
【发布时间】:2017-08-02 01:00:03
【问题描述】:

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

我有一个带有公共的抽象 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 中提供了一个很好的总结。

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

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

1) 我定义了一个 NodeIndex 类型,它是我未来迭代器的祖先。 (NodeIndex 在我的情况下是 std::vector<unsigned int>,但没关系。)

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

3) 我定义了一个TreeBasicIterator 类,继承自NodeIndex,出于连贯性目的,该类包括对BaseTree 的常量引用,并实现了各种迭代器方法(利用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 中抽象的部分好处。

BaseTreeNodeIndex 实例化为Iterator 类型将是多余的:实际上没有人会从该特定实例继承。

7) 预期:

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

8) 当前(临时?)部分可行的解决方案:

TreeNode 定义(通过通常的typedef)一个Iterator 类型(我的TreeBasicIterator 类)。它不会覆盖 BaseTree 中的 Iterator 类型,但可以。

BaseTree 有一个NodeIndex begin() const 方法,该方法既不隐藏,又在TreeNode 中通过Iterator begin() const 方法重载。它没有被覆盖。

同样,我在BaseTree 中有一个NodeIndex next_index(NodeIndex) const,它既未隐藏,又通过Iterator next_index(Iterator) const 方法在TreeNode 中重载。

【问题讨论】:

  • C++ 不能以这种方式工作。故事结束。
  • @Sam:我知道。我正在寻找一种可能比我在第 8 点中的解决方案更有效的替代方案)
  • 由于我是新人,也许 cmets 解释反对票会对我有所帮助

标签: c++ templates inheritance iterator


【解决方案1】:

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

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 的一次性编译方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-04
    • 1970-01-01
    • 2011-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多