在C++抽象类Collection中定义begin()和end()的实现难题
为多态Collection类适配范围for循环的可行方案
针对你的Collection抽象类因子类迭代器类型不同无法直接支持范围for循环的问题,以下是几种实用的解决方案:
方案1:基于类型擦除的统一迭代器接口
通过封装不同子类的迭代器行为,在抽象层提供统一的迭代器接口,让Collection可以直接支持范围for。
首先定义类型擦除的迭代基类,封装核心迭代操作:
class CollectionIterator { public: virtual ~CollectionIterator() = default; virtual int operator*() const = 0; virtual CollectionIterator& operator++() = 0; virtual bool operator!=(const CollectionIterator& other) const = 0; virtual std::unique_ptr<CollectionIterator> clone() const = 0; }; // 模板适配器,适配具体迭代器类型 template<typename Iter> class ConcreteIterator : public CollectionIterator { private: Iter iter; public: explicit ConcreteIterator(Iter iter) : iter(std::move(iter)) {} int operator*() const override { return *iter; } ConcreteIterator& operator++() override { ++iter; return *this; } bool operator!=(const CollectionIterator& other) const override { const auto* other_concrete = dynamic_cast<const ConcreteIterator*>(&other); return other_concrete == nullptr || iter != other_concrete->iter; } std::unique_ptr<CollectionIterator> clone() const override { return std::make_unique<ConcreteIterator>(iter); } };
修改Collection抽象类,添加纯虚函数返回迭代器,并提供适配范围for的代理对象:
class Collection { public: virtual ~Collection() = default; virtual std::unique_ptr<CollectionIterator> begin_iter() const = 0; virtual std::unique_ptr<CollectionIterator> end_iter() const = 0; // 范围for所需的迭代器代理 struct IteratorProxy { std::unique_ptr<CollectionIterator> iter; explicit IteratorProxy(std::unique_ptr<CollectionIterator> iter) : iter(std::move(iter)) {} int operator*() const { return **iter; } IteratorProxy& operator++() { ++*iter; return *this; } bool operator!=(const IteratorProxy& other) const { return *iter != *other.iter; } }; IteratorProxy begin() const { return IteratorProxy(begin_iter()); } IteratorProxy end() const { return IteratorProxy(end_iter()); } };
子类实现示例(以vector-backed集合为例):
class VectorCollection : public Collection { private: std::vector<int> vec; public: explicit VectorCollection(std::vector<int> vec) : vec(std::move(vec)) {} std::unique_ptr<CollectionIterator> begin_iter() const override { return std::make_unique<ConcreteIterator<std::vector<int>::const_iterator>>(vec.cbegin()); } std::unique_ptr<CollectionIterator> end_iter() const override { return std::make_unique<ConcreteIterator<std::vector<int>::const_iterator>>(vec.cend()); } };
使用范围for循环:
const Collection& coll = get_bounded_variables(); for (int val : coll) { // 处理每个元素 }
方案2:无侵入式代理遍历对象
如果无法修改原Collection接口,可以通过自由函数返回一个代理对象,封装现有for_each逻辑来支持范围for。
定义代理类和配套自由函数:
class CollectionRange { private: const Collection& coll; public: explicit CollectionRange(const Collection& coll) : coll(coll) {} class Iterator { private: const Collection& coll; mutable std::optional<int> current_val; mutable bool done = false; // 记录遍历进度的辅助函数(假设原for_each支持通过回调返回bool提前终止) void fetch_next() const { current_val.reset(); coll.for_each([this](int val) { if (!current_val.has_value()) { current_val = val; return false; // 终止for_each } return true; }); done = !current_val.has_value(); } public: Iterator(const Collection& coll, bool is_end) : coll(coll), done(is_end) { if (!done) fetch_next(); } int operator*() const { return *current_val; } Iterator& operator++() { fetch_next(); return *this; } bool operator!=(const Iterator& other) const { return done != other.done; } }; Iterator begin() const { return Iterator(coll, false); } Iterator end() const { return Iterator(coll, true); } }; CollectionRange iterate(const Collection& coll) { return CollectionRange(coll); }
使用方式:
const Collection& coll = get_bounded_variables(); for (int val : iterate(coll)) { // 处理每个元素 }
注:如果原for_each不支持提前终止,可改用异常捕获的方式终止遍历,或预先缓存所有元素(后者会带来额外内存开销)。
方案3:C++17+ 基于std::any的统一迭代器
利用C++17的std::any存储不同类型的迭代器,通过函数指针封装迭代操作,实现统一迭代器类型。
class CollectionIterator { private: std::any iter; int (*deref)(const std::any&) = nullptr; void (*increment)(std::any&) = nullptr; bool (*equal)(const std::any&, const std::any&) = nullptr; public: template<typename Iter> explicit CollectionIterator(Iter iter) : iter(std::move(iter)) { deref = [](const std::any& a) -> int { return *std::any_cast<const Iter&>(a); }; increment = [](std::any& a) { ++std::any_cast<Iter&>(a); }; equal = [](const std::any& a, const std::any& b) -> bool { return std::any_cast<const Iter&>(a) == std::any_cast<const Iter&>(b); }; } int operator*() const { return deref(iter); } CollectionIterator& operator++() { increment(iter); return *this; } bool operator!=(const CollectionIterator& other) const { return !equal(iter, other.iter); } }; class Collection { public: virtual ~Collection() = default; virtual CollectionIterator begin() const = 0; virtual CollectionIterator end() const = 0; }; // 子类实现示例 class RangeCollection : public Collection { private: int start; int end; public: RangeCollection(int start, int end) : start(start), end(end) {} CollectionIterator begin() const override { return CollectionIterator(std::views::iota(start, end).begin()); } CollectionIterator end() const override { return CollectionIterator(std::views::iota(start, end).end()); } };
方案选择建议
- 方案1是最正统的多态迭代实现,性能开销可控,适合长期维护的代码库。
- 方案2无侵入,无需修改原有
Collection接口,适合无法改动抽象类的场景。 - 方案3代码简洁,但依赖C17特性,且需保证
begin()和end()返回的迭代器类型一致,适合现代C环境。
内容的提问来源于stack exchange,提问作者Charlie Vanaret - the Uno guy
相关产品推荐
相关产品推荐

