你需要抛弃基于继承的多态性。标准库和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 是您迭代的类型,并且子类执行相同的操作(但返回的类支持++、*、复制构造和@987654347 @),它会表现出多态的值。
any_iterator_sorta 是一个 C++ 伪迭代器,足以在 for(:) 循环中工作,但不满足标准要求的真正 C++ 迭代器的所有公理。
live example
测试用例:
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) );
相同的代码,使用两种不同的迭代器实现进行迭代。
具体来说,假设您的代码遍历ints:
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:
class ArrayListIterator{
public:
int operator*() const { return 0; }
bool operator==( ArrayListIterator const& o ){return true;}
void operator++() { /* do nothing for now */ }
};
上面只包含 4 个必需操作的“存根”版本(复制构造、==、++ 和一元*),因此ArrayList 将在 C++ for(:) 循环中显示为“空” .