C++ 中的类型转换映射 <int, class A> 到 <int, class B>
TypeCasting Map <int, class A> to <int, class B> in C++
所以我有一个接受地图作为参数的函数,如下所示。
function do_dope_stuff(int arg1, std::map<uint32_t, parent_class>& my_object){
//do some programmer magic
}
然后从几个不同的地方调用这个函数,其中一个地图 ID 是一个 dervired 对象类型。
do_dope_stuff(int, std::map<uint32_t, child_class1>&)
or
do_dope_stuff(int, std::map<uint32_t, child_class2>&)
这显然行不通,因为地图的类型不同,因此没有匹配的函数调用。所以我的基本问题是我如何可以对地图进行类型转换以使其工作,而不必创建这个巨大地图的副本并将各个对象显式转换为兼容类型。因为 child_class 对象可以提升为父对象 class 但编译器不喜欢我尝试在映射上使用 C 样式转换。我也不想更改函数原型或重载它,因为它用于一个巨大的测试平台。
不太确定这是否是您要找的东西,或者它会起作用但是:
你可以
在函数定义中使用模板
有对象指针而不是对象的映射,并且复制指针比复制对象更便宜
传递一个指向地图的指针(或者可能是一个空指针)并在函数中重铸它
使用指向基(父class)的指针或引用,例如:
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&) {...}
您的设计存在问题,因为您的地图包含值。由于派生 class 的对象可能包含比父 class 的对象更多的数据,即使某些转换是可能的(但事实并非如此),也会有 slicing。
多态性方法
另一种方法可能是以多态方式设计您的 class,并在您的地图中存储不是对象值,而是指向对象的智能指针:
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>>
,映射中的元素是否包含指向父 class、子 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
}
所以我有一个接受地图作为参数的函数,如下所示。
function do_dope_stuff(int arg1, std::map<uint32_t, parent_class>& my_object){
//do some programmer magic
}
然后从几个不同的地方调用这个函数,其中一个地图 ID 是一个 dervired 对象类型。
do_dope_stuff(int, std::map<uint32_t, child_class1>&)
or
do_dope_stuff(int, std::map<uint32_t, child_class2>&)
这显然行不通,因为地图的类型不同,因此没有匹配的函数调用。所以我的基本问题是我如何可以对地图进行类型转换以使其工作,而不必创建这个巨大地图的副本并将各个对象显式转换为兼容类型。因为 child_class 对象可以提升为父对象 class 但编译器不喜欢我尝试在映射上使用 C 样式转换。我也不想更改函数原型或重载它,因为它用于一个巨大的测试平台。
不太确定这是否是您要找的东西,或者它会起作用但是: 你可以
在函数定义中使用模板
有对象指针而不是对象的映射,并且复制指针比复制对象更便宜
传递一个指向地图的指针(或者可能是一个空指针)并在函数中重铸它
使用指向基(父class)的指针或引用,例如:
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&) {...}
您的设计存在问题,因为您的地图包含值。由于派生 class 的对象可能包含比父 class 的对象更多的数据,即使某些转换是可能的(但事实并非如此),也会有 slicing。
多态性方法
另一种方法可能是以多态方式设计您的 class,并在您的地图中存储不是对象值,而是指向对象的智能指针:
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>>
,映射中的元素是否包含指向父 class、子 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
}