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 样式转换。我也不想更改函数原型或重载它,因为它用于一个巨大的测试平台。

不太确定这是否是您要找的东西,或者它会起作用但是: 你可以

  1. 在函数定义中使用模板

  2. 有对象指针而不是对象的映射,并且复制指针比复制对象更便宜

  3. 传递一个指向地图的指针(或者可能是一个空指针)并在函数中重铸它

使用指向基(父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 
}