编辑更短的问题: 当使用指向抽象类的指针时,如何调用它指向的对象的实际类型的方法?
我有一个带有公共
的抽象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
)提供的方法。
(我实际上有两个类:TreeBasicIterator
和Const_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
?)索引的排序详尽TreeVector
。 TreeNode
中的typedef
虚拟类型将是std :: iterator。
8)当前(临时?)部分工作解决方案:
Iterator
定义(通常是TreeBasicIterator
)Iterator
类型(我的BaseTree
类)。它不会覆盖BaseTree
中的NodeIndex begin() const
类型,但它可以。
TreeNode
有一个Iterator begin() const
方法,该方法既未被隐藏,又被NodeIndex next_index(NodeIndex) const
方法BaseTree
重载。它没有被覆盖。
同样地,我在TreeNode
中有一个Iterator next_index(Iterator) const
,它都是非隐藏的,并且{{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
的一劳永逸编译方法。