如何定义返回容器视图的纯虚函数?子类重写后输出不符预期
问题分析与解决方案
你的代码无法得到预期结果的核心原因是:虚函数返回std::ranges::view auto无法实现正确的多态重写。
C++的虚函数重写要求返回类型满足协变规则,而你代码中基类返回的std::views::all生成的all_view,与子类返回的std::views::transform生成的transform_view是完全不同的具体类型,且均为值类型,不满足协变条件。编译器会将子类的get_range视为独立的新方法,而非对基类虚函数的重写。因此通过基类指针调用时,实际执行的是基类的get_range,自然输出原向量内容。
修正方案
使用C++20提供的std::ranges::any_view<int>作为虚函数的统一返回类型,它通过类型擦除可以容纳任何符合input_range概念且元素为int的视图,让基类与子类的返回类型统一,从而实现正确的多态重写。
修正后的代码
#include <iostream> #include <ranges> #include <vector> class A { public: virtual auto get_range() const -> std::ranges::any_view<int> { return std::views::all(data); } protected: std::vector<int> data = {1, 2, 3, 4}; }; class B : public A { public: auto get_range() const -> std::ranges::any_view<int> override { std::cout << "B::get_range().." << std::endl; return data | std::views::transform([](int x) { return x * 2; }); } }; class C : public A { public: auto get_range() const -> std::ranges::any_view<int> override { std::cout << "C::get_range().." << std::endl; return data | std::views::transform([](int x) { return x * 3; }); } }; int main() { A* a = new A(); A* b = new B(); A* c = new C(); for (auto x : a->get_range()) { std::cout << x << " "; } std::cout << std::endl; for (auto x : b->get_range()) { std::cout << x << " "; } std::cout << std::endl; for (auto x : c->get_range()) { std::cout << x << " "; } std::cout << std::endl; delete a; delete b; delete c; return 0; }
其他可选方案
- 如果编译器不支持C++20的
any_view,可以直接返回std::vector<int>(在子类中先完成转换并生成新容器),但会带来额外的内存拷贝开销。 - 自定义多态范围包装类,手动实现类型擦除逻辑,但代码复杂度较高,适合对性能要求极高的场景。
内容的提问来源于stack exchange,提问作者peter
相关产品推荐
相关产品推荐

