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
相关产品推荐
相关产品推荐

