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

C++中如何抽象公共容器接口,使不同子类返回对应可迭代容器

C++ 实现多态可迭代容器接口的解决方案

标准库的vector、list等容器没有公共虚基类,原生不支持你想要的多态返回效果,你可以通过类型擦除实现运行时多态,或者CRTP实现编译期静态多态两种方式满足需求:

方案1:运行时多态(适配虚基类接口需求)

通过类型擦除封装统一的迭代器和可迭代范围接口,隐藏不同容器的实现差异,适合需要在运行时动态切换子类实现的场景。
示例代码如下:

#include <vector>
#include <list>
#include <memory>
#include <utility>
#include <iterator>

// 先定义统一的迭代器类型擦除类,示例元素类型为int,可改模板支持任意类型
class IntIterator {
    struct IteratorBase {
        virtual ~IteratorBase() = default;
        virtual const int& get() const = 0;
        virtual void increment() = 0;
        virtual bool equals(const IteratorBase& other) const = 0;
        virtual std::unique_ptr<IteratorBase> clone() const = 0;
    };

    template <typename Iter>
    struct IteratorImpl : IteratorBase {
        Iter iter;
        explicit IteratorImpl(Iter i) : iter(i) {}
        const int& get() const override { return *iter; }
        void increment() override { ++iter; }
        bool equals(const IteratorBase& other) const override {
            const auto* other_impl = dynamic_cast<const IteratorImpl<Iter>>(&other);
            return other_impl && iter == other_impl->iter;
        }
        std::unique_ptr<IteratorBase> clone() const override {
            return std::make_unique<IteratorImpl<Iter>>(iter);
        }
    };

    std::unique_ptr<IteratorBase> impl;
public:
    template <typename Iter>
    IntIterator(Iter iter) : impl(std::make_unique<IteratorImpl<Iter>>(iter)) {}
    IntIterator(const IntIterator& other) : impl(other.impl->clone()) {}
    IntIterator& operator=(const IntIterator& other) {
        impl = other.impl->clone();
        return *this;
    }

    const int& operator*() const { return impl->get(); }
    IntIterator& operator++() { impl->increment(); return *this; }
    bool operator==(const IntIterator& other) const { return impl->equals(*other.impl); }
    bool operator!=(const IntIterator& other) const { return !(*this == other); }
};

// 定义统一的可迭代范围类
class IntRange {
    struct RangeBase {
        virtual ~RangeBase() = default;
        virtual IntIterator begin() const = 0;
        virtual IntIterator end() const = 0;
    };

    template <typename Container>
    struct RangeImpl : RangeBase {
        Container cont;
        explicit RangeImpl(Container c) : cont(std::move(c)) {}
        IntIterator begin() const override { return IntIterator(cont.begin()); }
        IntIterator end() const override { return IntIterator(cont.end()); }
    };

    std::unique_ptr<RangeBase> impl;
public:
    template <typename Container>
    IntRange(Container&& c) : impl(std::make_unique<RangeImpl<std::decay_t<Container>>>(std::forward<Container>(c))) {}

    IntIterator begin() const { return impl->begin(); }
    IntIterator end() const { return impl->end(); }
};

// 你的虚基类
class Base {
public:
    virtual ~Base() = default;
    virtual IntRange getContainer() const = 0;
};

// 用vector的实现类
class A : public Base {
    std::vector<int> v = {1,2,3,4};
public:
    IntRange getContainer() const override {
        return v;
    }
};

// 用list的实现类
class B : public Base {
    std::list<int> l = {5,6,7,8};
public:
    IntRange getContainer() const override {
        return l;
    }
};

// 调用方用法
int main() {
    std::unique_ptr<Base> obj1 = std::make_unique<A>();
    std::unique_ptr<Base> obj2 = std::make_unique<B>();
    // 无需关心底层容器类型直接遍历
    for (auto val : obj1->getContainer()) { /* 处理元素 */ }
    for (auto val : obj2->getContainer()) { /* 处理元素 */ }
    return 0;
}

以上实现兼容所有STL标准容器,调用方不需要感知底层容器的具体类型。

方案2:编译期静态多态(CRTP)

如果编译期就能确定子类类型,不需要运行时动态调度,用CRTP实现没有虚函数开销,性能更高:

#include <vector>
#include <list>

template <typename Derived>
class Base {
public:
    auto getContainer() const {
        return static_cast<const Derived*>(this)->getContainerImpl();
    }
};

class A : public Base<A> {
    std::vector<int> v = {1,2,3};
public:
    const std::vector<int>& getContainerImpl() const {
        return v;
    }
};

class B : public Base<B> {
    std::list<int> l = {4,5,6};
public:
    const std::list<int>& getContainerImpl() const {
        return l;
    }
};

// 调用方用法
int main() {
    A a;
    B b;
    for (auto val : a.getContainer()) { /* 处理元素 */ }
    for (auto val : b.getContainer()) { /* 处理元素 */ }
    return 0;
}

这个方案不需要做类型擦除,直接返回对应容器的引用,性能最优,但只适合编译期能确定子类类型的场景。

内容的提问来源于stack exchange,提问作者Antilos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 23:09:03