如何在 C++ 中交换父指针和子指针?

问题描述

Weapon 继承自 Item

weapon 是类 Hero 的成员。我想将它与函数中传递的 item 交换,这也是本示例中的 Weapon(我将添加更多案例)。

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

基本上,当英雄的物品栏中装备了某物时,我希望它存储在 Hero 的相应成员中,而之前装备的 item 可以存储回物品栏中,无论项目的类型。库存是一个 std::vector<Item*>,因此它可以容纳多态项目。

向上转换 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*)'

解决方法

std::swap() 将非常量左值引用作为输入,这就是为什么当您尝试与 static_cast<Item*>(weapon) 交换时会收到“无匹配函数”错误的原因可以交换。

为了将新的 item 分配给 weapon 成员,您需要 Weapon* 返回的 dynamic_cast 指针,因此您的 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*& 参数使用 item 假定 equip() 是通过一个 Item* 指针直接inventory 元素,例如:

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

而不是间接,像这样:

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

如果传递给 itemequip() 不是对 inventory 元素的直接引用,那么我建议使用 {{1 }} 返回旧的 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;
}