class List{
public:
class ListIterator{
public:
};
typedef ListIterator iterator;
virtual iterator begin() = 0;
};
class ArrayList:public List{
public:
class ArrayListIterator{
public:
};
typedef ArrayListIterator iterator;
iterator begin(){
}
};
class LinkedList:public List{
public:
class LinkedListIterator{
public:
};
typedef LinkedListIterator iterator;
iterator begin(){
}
};
我想以这种方式实现迭代器。但编译器显示错误
[Error] invalid covariant return type for 'virtual ArrayList::iterator ArrayList::begin()'
[Error] overriding 'virtual List::iterator List::begin()'
LinkedList相同。
当我搜索堆栈溢出同样的问题时,我得到了这个解决方案
Iterator for custom container with derived classes 我得到两个解决方案
1 . implement iterator without using runtime polymorphism
2 . implement seperator iterator class.
但我想知道是否有任何可能的方式使迭代器成为ArrayList,LinkedList和List的内部类?
答案 0 :(得分:-1)
您需要ArrayListIterator从ListIterator派生。
派生类中begin返回的类型不是从基类List类中的begin返回的类型派生的。
这就是为什么错误说它们不是协变的。
答案 1 :(得分:-1)
你需要抛弃基于继承的多态性。标准库和for(:)
循环中的C ++迭代假定基于值的迭代器,基于继承的多态不适用于基于值的迭代器。
您应该使用基于类型擦除的多态性,而不是基于继承的多态性。这需要一些样板,因为在C ++中发现需要抽象地处理可迭代范围的需求并不常见,并且通常会造成严重的性能损失。
但我会告诉你如何。
基于类型擦除的多态性类似于std::function
。
类型擦除多态的一种具体方法:
您可以确定要支持的界面。将此称为"类型擦除目标"。您的类型擦除目标是不具有virtual
和=0
的类,而是您要支持的一组函数,方法和操作,以及它们的签名和描述各自做了什么。
然后编写一个实现的值类,该接口(同样,没有继承)包含一个pImpl
(参见pImpl
模式),它将其操作分派给( pImpl
不需要匹配相同的接口,它只需要你可以实现操作的原语。这里最小的是值得的。)
pImpl
类型 具有virtual
方法和=0
抽象方法。
然后编写一个构造函数或工厂函数,它接受一个支持你想要的接口的对象,并生成pImpl
的具体实例,然后在其周围包装值类。
假设类型擦除目标是"打印到流"。
我的类型擦除目标是std::ostream& << foo
可以工作,并打印东西。
struct printable_view {
// dispatch to pimpl:
friend std::ostream& operator<<( std::ostream& o, printable_view const& p ) {
p->print(o);
return o;
}
// pimpl:
private:
struct printable_view_impl {
virtual ~printable_view_impl() {}
virtual void print(std::ostream& o) = 0;
};
std::unique_ptr<printable_view_impl> pImpl;
private:
template<class T>
struct printer:printable_view_impl {
printer( T const* p ):ptr(p) {}
T const* ptr; // just a view, no ownership
virtual void print( std::ostream& o ) final override {
o << *ptr;
}
};
public:
// create a pimpl:
printable_view(printable_view&&)=default;
printable_view(printable_view const&)=delete;
printable_view()=delete;
template<class T>
printable_view( T const& t ):
pImpl( std::make_unique<printer<T>>( std::addressof(t) ) )
{}
};
可能有错别字,但你明白了。
如果要查找示例实现,Boost has a generic iterator and range您的基类可以返回。
使用基于类型擦除的迭代有很大的性能提升:你最终会得到与C#/ Java代码一样慢的C ++代码。
在你的情况下,你需要按照标准的要求, iterator
要求的每个事物(复制,增加,移动,取消引用等),并像我复制一样删除它。在这种情况下,它不是一个视图,因此您的impl impl可能会包含T
而不是T*
。
这是一个非常简单的玩具for(:)
,它支持玩具伪迭代器,允许你的List
基地在for(:)
循环中使用。
template<class T>
struct any_iterator_sorta {
T operator*()const { return pImpl->get(); }
void operator++() { pImpl->next(); }
any_iterator_sorta(any_iterator_sorta const& o):
any_iterator_sorta( o.pImpl?any_iterator_sorta(o.pImpl->clone()):any_iterator_sorta() )
{}
friend bool operator==(any_iterator_sorta const& lhs, any_iterator_sorta const& rhs ) {
if (!lhs.pImpl || ! rhs.pImpl)
return lhs.pImpl == rhs.pImpl;
return lhs.pImpl->equals( *rhs.pImpl );
}
friend bool operator!=(any_iterator_sorta const& lhs, any_iterator_sorta const& rhs ) {
return !(lhs==rhs);
}
any_iterator_sorta(any_iterator_sorta&& o) = default;
any_iterator_sorta() = default;
any_iterator_sorta& operator=(any_iterator_sorta const& o) {
any_iterator_sorta tmp=o;
std::swap(tmp.pImpl, o.pImpl);
return *this;
}
any_iterator_sorta& operator=(any_iterator_sorta&& o) = default;
private:
struct pimpl {
virtual ~pimpl() {}
virtual void next() = 0;
virtual T get() const = 0;
virtual std::unique_ptr< pimpl > clone() const = 0;
virtual bool equals( pimpl const& rhs ) const = 0;
};
std::unique_ptr< pimpl > pImpl;
template<class It>
struct pimpl_impl:pimpl {
It it;
virtual void next() final override { ++it; }
virtual T get() const final override { return *it; }
virtual std::unique_ptr< pimpl > clone() const final override {
return std::make_unique<pimpl_impl>( it );
}
virtual bool equals( pimpl const& rhs ) const final override {
if (auto* r = dynamic_cast<pimpl_impl const*>(&rhs))
return it == r->it;
return false;
}
pimpl_impl( It in ):it(std::move(in)) {}
};
any_iterator_sorta( std::unique_ptr< pimpl > pin ):pImpl(std::move(pin)) {}
public:
template<class It,
std::enable_if_t< !std::is_same<It, any_iterator_sorta>{}, int>* =nullptr
>
any_iterator_sorta( It it ):
pImpl( std::make_unique<pimpl_impl<It>>( std::move(it) ) )
{}
};
如果您的接口类返回any_iterator_sorta<T>
,其中T
是您迭代的类型,并且子类执行相同的操作(但返回了支持++
的类,{{1复制构造和*
),它会表现为多态的值。
==
是一个C ++伪迭代器,它足以在any_iterator_sorta
循环中工作,但不能满足标准规定的真正C ++迭代器的所有公理。
测试用例:
for(:)
相同的代码,使用两个不同的迭代器实现进行迭代。
具体而言,假设您的代码迭代void test( any_iterator_sorta<int> begin, any_iterator_sorta<int> end )
{
for (auto it = begin; it != end; ++it) {
std::cout << *it << '\n';
}
}
std::vector<int> v{1,2,3};
std::list<int> l{10,11};
test( begin(v), end(v) );
test( begin(l), end(l) );
s:
int
virtual any_iterator_sorta<int> begin() = 0;
virtual any_iterator_sorta<int> end() = 0;
中的。然后在List
:
ArrayList
最后,实施 any_iterator_sorta<int> begin() final override {
return ArrayListIterator{};
}
any_iterator_sorta<int> end() final override {
return ArrayListIterator{};
}
:
ArrayListIterator
上面只包含&#34; stub&#34; 4个必需操作的版本(复制构造, class ArrayListIterator{
public:
int operator*() const { return 0; }
bool operator==( ArrayListIterator const& o ){return true;}
void operator++() { /* do nothing for now */ }
};
,==
和一元++
),因此*
将出现&#34;空&#34;到C ++ ArrayList
循环。