C++中遍历多向量调用父类方法的实现方案
问题:遍历多个子类向量统一调用父类方法
现有代码结构
父类定义
class Parent { public: virtual ~Parent() = default; virtual void method1() = 0; virtual void method2() = 0; virtual void method3() = 0; };
子类定义
class Child1: public Parent { void method1() override; void method2() override; void method3() override; }; class Child2: public Parent { void method1() override; void method2() override; void method3() override; };
Controller类
class Controller{ private: std::vector<Child1*> childs1; std::vector<Child2*> childs2; };
尝试方案及问题
需求是无需为每个向量单独编写for循环,遍历所有子类向量的元素并调用父类虚方法。
尝试过将向量转换为std::vector<Parent*>后存入列表再遍历,但该方案存在两个问题:
- 向量大小异常,比如原
childs1.size()为4时,新向量会尝试访问第5个元素,且列表中元素的大小远大于原向量; - 会创建整个向量的副本,产生不必要的性能开销。
解决方案
方案1:直接使用容器引用列表(C++11+,无额外依赖)
通过将多个子类向量转换为std::vector<Parent*>的引用,存入初始化列表后遍历,避免复制整个向量:
// 在Controller的成员函数中实现 void processAll() { // 用reinterpret_cast安全转换容器类型,Child*可隐式转为Parent*,内存布局兼容 std::initializer_list<const std::vector<Parent*>*> all_vecs = { reinterpret_cast<const std::vector<Parent*>*>(&childs1), reinterpret_cast<const std::vector<Parent*>*>(&childs2) }; for (auto vec_ptr : all_vecs) { for (Parent* p : *vec_ptr) { p->method1(); p->method2(); p->method3(); } } }
优点:实现简单,无额外代码,无向量复制,性能开销极小。
方案2:自定义拼接迭代器(兼容C++11及以上)
如果需要更通用的遍历方式,可以实现一个自定义范围类,其迭代器会自动从一个容器的末尾跳转到下一个容器的开头:
#include <vector> #include <iterator> template <typename Container> class ConcatenatedRange { public: using Iterator = typename Container::const_iterator; explicit ConcatenatedRange(std::initializer_list<const Container*> containers) : m_containers(containers), m_current_container(m_containers.begin()) { if (m_current_container != m_containers.end()) { m_current_it = (*m_current_container)->begin(); advance_to_valid(); } } // 自定义迭代器包装类 class IteratorWrapper { public: using value_type = typename Iterator::value_type; using reference = typename Iterator::reference; using pointer = typename Iterator::pointer; using difference_type = std::ptrdiff_t; using iterator_category = std::forward_iterator_tag; IteratorWrapper() = default; IteratorWrapper(typename std::vector<const Container*>::const_iterator container_it, Iterator it) : m_container_it(container_it), m_it(it) {} reference operator*() const { return *m_it; } pointer operator->() const { return &(*m_it); } IteratorWrapper& operator++() { ++m_it; if (m_it == (*m_container_it)->end()) { ++m_container_it; if (m_container_it != std::vector<const Container*>::const_iterator()) { m_it = (*m_container_it)->begin(); } } return *this; } bool operator==(const IteratorWrapper& other) const { if (m_container_it != other.m_container_it) return false; return m_it == other.m_it; } bool operator!=(const IteratorWrapper& other) const { return !(*this == other); } private: typename std::vector<const Container*>::const_iterator m_container_it; Iterator m_it; }; IteratorWrapper begin() const { return IteratorWrapper(m_containers.begin(), m_current_it); } IteratorWrapper end() const { return IteratorWrapper(m_containers.end(), Iterator()); } private: // 跳过空容器,直接定位到第一个有元素的容器 void advance_to_valid() { while (m_current_container != m_containers.end() && m_current_it == (*m_current_container)->end()) { ++m_current_container; if (m_current_container != m_containers.end()) { m_current_it = (*m_current_container)->begin(); } } } std::vector<const Container*> m_containers; typename std::vector<const Container*>::const_iterator m_current_container; Iterator m_current_it; }; // 使用方式 void Controller::processAll() { ConcatenatedRange<std::vector<Parent*>> range({ reinterpret_cast<const std::vector<Parent*>*>(&childs1), reinterpret_cast<const std::vector<Parent*>*>(&childs2) }); for (Parent* p : range) { p->method1(); p->method2(); p->method3(); } }
优点:通用性强,后续新增子类向量只需在初始化列表中添加即可,遍历逻辑统一;无元素复制,效率高。
方案3:C++20范围库(最简洁)
如果项目支持C++20,可利用标准库的范围适配器实现零复制的拼接遍历:
#include <ranges> void Controller::processAll() { // 将子类向量转为Parent*的视图,无复制 auto view1 = childs1 | std::views::transform([](Child1* c) -> Parent* { return c; }); auto view2 = childs2 | std::views::transform([](Child2* c) -> Parent* { return c; }); // 拼接两个视图 auto combined_view = std::views::concat(view1, view2); for (Parent* p : combined_view) { p->method1(); p->method2(); p->method3(); } }
优点:代码最简洁,利用标准库实现,无需自定义代码,完全零复制,性能最优。
内容的提问来源于stack exchange,提问作者user25421183
相关产品推荐
相关产品推荐

