所以我有一个接受地图作为参数的函数,如下所示。
function do_dope_stuff(int arg1, std::map<uint32_t, parent_class>& my_object){
//do some programmer magic
}
然后从几个不同的地方调用此函数,其中一个地图ID是一个衍生对象类型。
do_dope_stuff(int, std::map<uint32_t, child_class1>&)
or
do_dope_stuff(int, std::map<uint32_t, child_class2>&)
这显然不起作用,因为没有匹配的函数调用,因为映射是不同类型的。所以我的基本问题是如何在不必创建这个巨大地图的副本并将各个对象显式转换为兼容类型的情况下对地图进行类型转换。因为child_class对象可以提升为父类,但编译器并不喜欢我尝试在地图上使用C样式转换。我也不想改变函数原型或重载它,因为它在一个巨大的测试平台中使用。
答案 0 :(得分:2)
不太确定这是否是您正在寻找的,或者它会起作用但是: 你可以
在功能定义中使用模板
有一个映射到对象指针而不是对象,并复制比复制对象便宜的指针
传递一个指向地图的指针(或者可能是一个无效指针)并在函数中重铸
答案 1 :(得分:1)
使用指针或对基类(父类)的引用,例如:
void do_dope_stuff(int arg1, std::map<uint32_t, parent_class&>& my_object){
//do some programmer magic
}
void do_dope_stuff(int, std::map<uint32_t, parent_class&>&) {...}
void do_dope_stuff(int, std::map<uint32_t, parent_class&>&) {...}
或者如果你想要静态多态,那么使用模板,例如:
template<typename T>
void do_dope_stuff(int arg1, T& my_object){
//do some programmer magic
}
template<typename T>
void do_dope_stuff(int, T&) {...}
template<typename T>
void do_dope_stuff(int, T&) {...}
答案 2 :(得分:1)
您的设计存在的问题是您的地图包含值。由于派生类的对象可能包含的数据多于父类的对象,即使某些转换是可能的(它不是),也会有slicing。
多态性方法
另一种方法可能是以多种方式设计您的类,并在地图中存储而不是对象值,而是存储到对象的智能指针:
std::map<uint32_t, shared_ptr<parent_class>> my_map;
my_map[777]=make_shared<parent_class>();
my_map[911]=make_shared<child_class>(); // you can mix !
my_map[89]=make_shared<parent_class>();
do_dope_stuff(1, my_map);
为了使其按预期工作,您需要为子项具有与父项不同的行为的每个函数使用虚函数:
struct parent_class {
virtual void say_hello() { cout << "Hello, I'm parent"<<endl; }
virtual ~parent_class() {}
};
struct child_class : parent_class {
void say_hello() override { cout << "Hello, I'm child"<<endl; }
};
您的do_dope_function()
可以享受多态性并处理std::map<uint32_t, shared_ptr<parent_class>>
,无论地图中的元素是否包含指向父类,子类或两者的混合的指针。
采用多态和模板方法
当然,这并不能解决您拥有std::map<uint32_t, shared_ptr<child_class>>
的情况。但是,当你的设计现在允许更灵活的多态容器时,你真的需要这样一个特定的地图吗?
如果是,您可以通过将您的功能定义为模板来扩展解决方案。示例:
template <typename T>
void do_dope_stuff(int arg1, std::map<uint32_t, shared_ptr<T>>& my_object){
//do some programmer magic
for (auto &x:my_object) {
cout << x.first<<": ";
x.second->say_hello();
}
}
此处 live demo 结束了不同的案例。
仅限模板,如果您想坚持原始设计
但也许您希望坚持初始设计,在地图中保留值,并避免多态性。
然后您可以将您的功能定义为模板。但是,您需要在编译时知道地图中必须处理的对象类型,然后地图中的所有对象必须属于同一类型。这看起来像是:
template <typename T>
void do_dope_stuff(int arg1, std::map<uint32_t, T>& my_object) {
//do some programmer magic
}