You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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*>后存入列表再遍历,但该方案存在两个问题:

  1. 向量大小异常,比如原childs1.size()为4时,新向量会尝试访问第5个元素,且列表中元素的大小远大于原向量;
  2. 会创建整个向量的副本,产生不必要的性能开销。

解决方案

方案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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 22:02:33