首页 > 解决方案 > 如何在 C++ 中交换父指针和子指针?

问题描述

Weapon继承自Item

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

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

基本上,当从英雄的物品栏中装备某物时,我希望它存储在 的相应成员中Heroitem而之前装备的物品将重新存储在物品栏中,无论物品类型如何。库存是一个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*)' 没有匹配的函数

标签: c++inheritancecastingpolymorphisminstanceof

解决方案


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

为了将新成员分配itemweapon成员,您需要返回的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*&foritem参数的使用假定使用直接取自元素的指针equip()调用它,例如:Item*inventory

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

而不是间接的,像这样:

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

如果item传入的equip()不是直接引用的元素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);

推荐阅读