C++:父子类指针的Optional Map能否跨类型作为函数参数传递?
C++ std::map与可选指针的类型转换问题
问题描述
能否将存储std::optional<子类指针>的std::map作为实参,传入参数为存储std::optional<父类指针>的std::map的函数?
示例代码如下:
#include <iostream> #include <string> #include <optional> #include <map> #include <memory> using namespace std; class A { public: virtual void f() = 0; }; //抽象类 class B : public A { public: void f() override { std::cout <<"override only" << std::endl; } }; void testFunction(std::map<int, std::optional<std::shared_ptr<B>>>) { std::cout << "success!" << std::endl; } int main() { std::map<int, std::optional<std::shared_ptr<A>>> map; testFunction(map); return 0; }
编译时抛出错误:
main.cpp:27:18: error: could not convert ‘map’ from ‘map<[...],optional>>’ to ‘map<[...],optional>>’
衍生疑问
- 报错原因是
std::optional还是std::map导致的?(本人认为是std::map的问题,因为std::map<int, 父类>同样无法转换) - 是否存在方法可以传递存储
std::optional<子类指针>的std::map? - 简化版本(仅在map中存储指针)能否实现如下代码的功能?
void testFunction(std::map<int, std::shared_ptr<B>>) { std::cout << "success!" << std::endl; } int main() { std::map<int, std::shared_ptr<A>> map; testFunction(map); }
解答
报错原因
确实是std::map导致的,和std::optional无关。
- C++中容器的类型由其模板参数严格决定,
std::map<K, V1>和std::map<K, V2>属于完全不同的类型,哪怕V1可以隐式转换为V2,容器本身也不能直接进行类型转换。 - 你提到的
std::map<int, 父类>无法转换为std::map<int, 子类>的情况,本质也是这个原因——容器模板参数必须完全匹配才能直接传递。
传递存储std::optional<子类指针>的std::map的方法
直接传递原容器不行,但可以通过两种方式实现需求:
- 手动转换容器:创建目标类型的
std::map,逐个元素转换后传入。由于std::optional<std::shared_ptr<B>>可以隐式转换为std::optional<std::shared_ptr<A>>(B继承自A),遍历源map并插入新map即可:
std::map<int, std::optional<std::shared_ptr<A>>> src_map; // 填充src_map... std::map<int, std::optional<std::shared_ptr<B>>> dest_map; for (const auto& pair : src_map) { dest_map.insert(pair); } testFunction(dest_map);
- 修改函数参数类型:将函数改为模板函数,或者接受
std::map<int, std::optional<std::shared_ptr<A>>>类型的参数,在函数内部用dynamic_pointer_cast检查指针类型:
void testFunction(const std::map<int, std::optional<std::shared_ptr<A>>>& map) { for (const auto& [key, opt_ptr] : map) { if (opt_ptr) { auto b_ptr = std::dynamic_pointer_cast<B>(*opt_ptr); if (b_ptr) { // 处理B类型指针的逻辑 b_ptr->f(); } } } std::cout << "success!" << std::endl; }
简化版本的可行性
你给出的简化版本代码无法直接运行,原因和之前一致:std::map<int, std::shared_ptr<A>>与std::map<int, std::shared_ptr<B>>是不同的容器类型,不能直接转换。要实现类似功能,同样需要手动转换容器,或者修改函数参数为std::map<int, std::shared_ptr<A>>并在内部做类型判断。
内容的提问来源于stack exchange,提问作者PepperGooooo
相关产品推荐
相关产品推荐

