如何定义可接收各类迭代器的C++纯虚insert方法?
标准库没有提供现成的通用迭代器包装可以直接作为虚函数参数使用,以下是两种可以实现需求的可行方案:
方案1:NVI(非虚接口)模式(推荐优先使用)
这是工业界最常用的折衷方案,实现成本极低,不需要改动调用方代码,完美兼容所有迭代器类型和移动语义:
核心思路是对外暴露非虚的模板接口,内部将迭代器范围转换为统一的格式后调用虚函数实现。
示例代码如下:
#include <vector> #include <mutex> #include <utility> class Class { /* 你自己的元素类型 */ }; class Base { public: virtual ~Base() = default; // 对外的非虚模板接口,兼容所有迭代器类型 template<typename Iter> void insert(Iter begin, Iter end) { // 把迭代器范围转换为统一的vector<Class>,自动适配移动语义 insert_impl(std::vector<Class>( std::make_move_iterator(begin), std::make_move_iterator(end) )); } private: // 纯虚实现函数,参数是统一类型,派生类只需要实现这个接口 virtual void insert_impl(std::vector<Class> elements) = 0; }; // 线程安全派生类实现 class DerivedMT : public Base { private: std::vector<Class> v; std::mutex mtx; void insert_impl(std::vector<Class> elements) override { std::lock_guard<std::mutex> lock(mtx); // 用RAII管理锁,避免异常死锁 v.insert(v.end(), elements.begin(), elements.end()); } }; // 带观察者通知的派生类实现 class DerivedObserved : public Base { private: std::vector<Class> v; void notifyObservers() { /* 你的通知逻辑 */ } void insert_impl(std::vector<Class> elements) override { v.insert(v.end(), elements.begin(), elements.end()); notifyObservers(); } };
优缺点
- 优点:代码简单易维护,完全兼容所有STL迭代器,自动支持移动语义,调用方不需要做任何修改
- 缺点:多了一次元素的移动/拷贝开销,对于超大对象或者性能敏感场景可以考虑下一种方案
方案2:实现类型擦除的通用输入迭代器
如果你需要完全消除额外的移动/拷贝开销,可以自己实现针对Class类型的类型擦除迭代器,也就是你代码里要的GenericIter,核心思路是用多态把不同迭代器的++、*、==操作封装到抽象基类里,对外暴露统一的迭代器接口。
简化实现示例:
#include <memory> #include <iterator> class AnyInputIter { public: using value_type = Class; using difference_type = std::ptrdiff_t; using pointer = const Class*; using reference = const Class&; using iterator_category = std::input_iterator_tag; template<typename Iter> AnyInputIter(Iter iter) : impl_(std::make_unique<IterModel<Iter>>(iter)) {} AnyInputIter(const AnyInputIter& other) : impl_(other.impl_->clone()) {} AnyInputIter& operator=(const AnyInputIter& other) { impl_ = other.impl_->clone(); return *this; } reference operator*() const { return impl_->deref(); } pointer operator->() const { return &impl_->deref(); } AnyInputIter& operator++() { impl_->inc(); return *this; } AnyInputIter operator++(int) { AnyInputIter tmp = *this; impl_->inc(); return tmp; } bool operator==(const AnyInputIter& other) const { return impl_->equal(other.impl_.get()); } bool operator!=(const AnyInputIter& other) const { return !(*this == other); } private: struct IterConcept { virtual ~IterConcept() = default; virtual std::unique_ptr<IterConcept> clone() const = 0; virtual void inc() = 0; virtual reference deref() const = 0; virtual bool equal(const IterConcept* other) const = 0; }; template<typename Iter> struct IterModel : IterConcept { Iter iter; IterModel(Iter i) : iter(i) {} std::unique_ptr<IterConcept> clone() const override { return std::make_unique<IterModel>(iter); } void inc() override { ++iter; } reference deref() const override { return *iter; } bool equal(const IterConcept* other) const override { const auto* other_model = dynamic_cast<const IterModel*>(other); return other_model && iter == other_model->iter; } }; std::unique_ptr<IterConcept> impl_; };
你就可以直接用AnyInputIter作为虚函数的参数:
class Base { public: virtual void insert(AnyInputIter begin, AnyInputIter end) = 0; }; // 派生类实现和你示例代码完全一致
优缺点
- 优点:没有额外的元素移动/拷贝开销,性能和原生迭代器接近
- 缺点:需要自己维护类型擦除代码,实现复杂度更高,上面的示例只支持输入迭代器,如果需要支持前向/双向/随机访问迭代器需要额外扩展
注意事项
- 不要手动调用
mutex.lock()和mutex.unlock(),使用std::lock_guard或std::unique_lock等RAII工具,避免抛出异常时出现死锁 std::move_iterator只是迭代器适配器,作用是将解引用结果转换为右值引用,本身不能实现不同类型迭代器的类型统一- 如果项目允许引入第三方库,可以直接使用Boost提供的
boost::any_iterator,不需要自己实现类型擦除逻辑
内容的提问来源于stack exchange,提问作者ManuelSchneid3r
相关产品推荐
相关产品推荐

