【问题标题】:How can I swap a parent pointer and a child pointer in c++?如何在 C++ 中交换父指针和子指针?
【发布时间】:2021-05-27 08:58:21
【问题描述】:

Weapon 继承自 Item

weaponHero 类的成员。我想将其与函数中传递的item 进行交换,对于本示例,它也是Weapon(我将添加更多案例)。

void Hero::equip(Item* item){
    
    if(instanceof<Weapon>(item)){std::swap (item, static_cast<Item>(weapon));}
}

基本上,当从英雄的库存中装备某些东西时,我希望它存储在Hero的相应成员中,而之前装备的item将重新存储在库存中,无论项目类型。库存是std::vector&lt;Item*&gt;,因此它可以容纳多态物品。

向上转换weapon 似乎不起作用,因为Item 是虚拟的。我尝试过的所有其他类型的铸造也失败了,一些手动交换它们的尝试也是如此。如果您想知道 instanceof,我复制了这个模板,以便在 C++ 中使用它:

template<typename Base, typename T> 
inline bool instanceof(const T *ptr) {
    return dynamic_cast<const Base*>(ptr) != nullptr;
}

当我使用Item* 而不是Item 时,我得到:

调用'swap(Item*&, Item*)'没有匹配的函数

【问题讨论】:

  • 提示:你不想交换Items,你想交换Item*s
  • 另外,在处理多态性时,您要查找的演员表是 dynamic_cast
  • 你为什么使用交换而不是替换? weapon 的确切声明是什么?
  • 您可能应该想出一个更完整的minimal reproducible example,因为您当前的代码似乎有几个缺陷。 (例如,与Item* 类型的参数交换不会影响库存,但Item*&amp; 可能。)最好显示给出错误消息的代码,因为可能在正确的轨道。
  • @GeorgeT 您可能有兴趣阅读Markdown Editing Help,尤其是“代码跨度”部分。

标签: c++ inheritance casting polymorphism instanceof


【解决方案1】:

std::swap() 将非 const 左值引用作为输入,这就是为什么当您尝试与 static_cast&lt;Item*&gt;(weapon) 交换时会收到“无匹配函数”错误,因为它没有返回可以交换的左值。

为了将新的item 分配给weapon 成员,您需要dynamic_cast 返回的Weapon* 指针,因此您的instanceof() 模板在这里没有帮助。

试试这个:

void Hero::equip(Item* &item) {
    if (Weapon *new_weapon = dynamic_cast<Weapon*>(item)) {
        Item *old_weapon = weapon;
        weapon = new_weapon;
        item = old_weapon;
    }
}

或者:

void Hero::equip(Item* &item) {
    if (Weapon *w = dynamic_cast<Weapon*>(item)) {
        std::swap(weapon, w);
        item = w;
    }
}

或者,如果您使用的是 C++14 或更高版本,则可以改用 std::exchange()

void Hero::equip(Item* &item) {
    if (Weapon *new_weapon = dynamic_cast<Weapon*>(item)) {
        item = std::exchange(weapon, new_weapon);
    }
}

注意:将Item*&amp; 用于item 参数假定equip() 是通过从inventory 元素直接 获取的Item* 指针调用的,例如:

hero.equip(hero.inventory[index]);

而不是间接,像这样:

Item *item = hero.inventory[index];
hero.inventory.erase(hero.inventory.begin()+index);
hero.equip(item);

如果传递给equip()item 不是对inventory 元素的直接 引用,那么我建议让equip() 返回旧的Item*并让调用者决定如何处理它,例如:

Item* Hero::equip(Item* item) {
    if (Weapon *new_weapon = dynamic_cast<Weapon*>(item)) {
        Item *old_weapon = weapon;
        weapon = new_weapon;
        return old_weapon;
    }
    ...
    return nullptr;
}

或者:

Item* Hero::equip(Item* item) {
    if (Weapon *w = dynamic_cast<Weapon*>(item)) {
        std::swap(weapon, w);
        return w;
    }
    ...
    return nullptr;
}

或者:

Item* Hero::equip(Item* item) {
    if (Weapon *new_weapon = dynamic_cast<Weapon*>(item)) {
        return std::exchange(weapon, new_weapon);
    }
    ...
    return nullptr;
}

然后调用者可以这样做:

Item *item = hero.inventory[index];
hero.inventory.erase(hero.inventory.begin()+index);
item = hero.equip(item);
if (item) hero.inventory.push_back(item);

【讨论】:

  • @MooingDuck that won't work:“没有匹配函数调用‘swap(Item*&, Weapon*&)’”。 std::swap() 的输入必须是相同的类型,因此在这种情况下必须强制转换其中一个。
  • @RemyLebeau 再次感谢!这有点接受,但我现在明白了。只能从库存中进行装备,所以我将使用您的第一个示例。
  • @MooingDuck nope,that won't work, either:“没有匹配函数调用‘swap(Item*&, Weapon*&)’”。 std::swap() 通过引用获取其参数。您可以将Weapon* 传递给Item*,将Weapon&amp; 传递给Item&amp;,但不能将Weapon*&amp; 传递给Item*&amp;
最近更新 更多