C++ C++;当我不使用';我不认识孩子们;类型

C++ C++;当我不使用';我不认识孩子们;类型,c++,polymorphism,base-class,C++,Polymorphism,Base Class,我有一个存储“InventoryItem”的库存 struct InventoryItem{ Item* item; unsigned int quantity;}; std::vector<InventoryItem> m_items; 已经在绷带课上宣布过了 // .... class Bandage : public Item{ public: // .... virtual void use(Player&); // .... void

我有一个存储“InventoryItem”的库存

struct InventoryItem{
Item* item;
unsigned int quantity;};

std::vector<InventoryItem> m_items;
已经在绷带课上宣布过了

   // ....
class Bandage : public Item{
public:
   // ....
    virtual void use(Player&);
   // ....
void Bandage::use(Player& player)
{
    player.heal(35);
} 
它在绷带类中有这样的定义

   // ....
class Bandage : public Item{
public:
   // ....
    virtual void use(Player&);
   // ....
void Bandage::use(Player& player)
{
    player.heal(35);
} 
当我试图调用我物品的
use()
函数时,比如说,
m_items.at(I).item->use(*m_player)

它调用基类'Item'
use()
函数,而不是'Bandage'
use()
函数

编辑: 这是我的addItem函数

void Inventory::addItem(const Item& item)
{
    if ((m_items.size() < m_capacity))
    {
        bool foundItem(false);
        for (auto invItem : m_items)
        {
            // if the item already exists, lets just increase the quantity
            if (invItem.item->getID() == item.getID())
            {
                foundItem = true;
                if (invItem.quantity < invItem.item->getInventoryQuantityLimit())
                {
                    ++invItem.quantity;
                }
            }
        }

        if (!foundItem){
            m_items.push_back(InventoryItem{ new Item(item), 1 });
        }

    }
}
void Inventory::addItem(常量项目和项目)
{
如果((m_items.size()getID()==item.getID())
{
foundItem=true;
if(invItem.quantitygetInventoryQuantityLimit())
{
++数量;
}
}
}
如果(!foundItem){
m_items.push_back(InventoryItem{newitem(Item),1});
}
}
}

问题出在您的
addItem()
函数中,更准确地说是:

m_items.push_back(InventoryItem{ new Item(item), 1 });
InventoryItem
中的指针
Item*
最终指向
,而不是指向从
派生的对象,即使
是派生对象。表达式
newitem(Item)
不创建派生对象,而是调用
Item
的复制构造函数(如果您没有编写它,则为默认值),并将派生对象
Item
作为参数。然后,它在堆上创建
对象,并返回指向它的指针


您最好使用工厂方法来创建所需的项,并摆脱原始指针,转而使用
std::shared_ptr
(或
std::unique_ptr
,尽管可能在这里
std::shared_ptr
更好)。

很难看出有什么错误,但也许在你的循环中使用auto会把事情搞砸。作为一个快速测试,您可以尝试添加一个静态强制转换,以验证auto没有扰乱虚拟函数的分辨率。

如前所述,行
新建项(项)
创建一个基(
),而不是派生对象

如果您真的想要克隆对象而不是只保留提供的指针(最好使用<代码> AutoPPTR <代码> >,请考虑将<代码>克隆()/代码>函数添加到<代码>项目和派生类:

class Item {
    ...
    virtual Item* clone() { return new Item(*this);}
}

class Bandage : public Item {
    ...
    virtual Bandage* clone() { return new Bandage(*this); }
}

....
m_items.push_back(InventoryItem{ item.clone(), 1 });

有两种可能的解决方案:

首先,如果物品是无状态的,您可以实现这一点,使游戏中每种类型只有一件物品,并与所有玩家共享该物品的所有权(如果物品不是无状态的,则使用该物品的玩家在不同线程上使用时会影响其他玩家的库存状态,或导致未定义的行为)

代码更改(对于无状态项实现):

struct InventoryItem{
std::shared_ptr item;//使用
//此(无状态)项将共享所有权
无符号整数数量;
};
无效库存::附加项(常量项目和项目)
{
如果((m_items.size()

其次,如果项目不是无状态的,则必须有一个虚拟克隆方法(允许每个专门化克隆它自己的专门化类型)

实施变化:

class item {
    // rest of class here ...
public:
    virtual std::shared_ptr<item> clone() const = 0;
};

class bandage {
public:
    std::shared_ptr<item> clone() const override
    {
        return std::shared_ptr<item>{ new bandage{ *this } }; // use bandage copy constructor
                                     // and instantiate concrete item type
    }
};

void Inventory::addItem(const Item& item)
{
    if ((m_items.size() < m_capacity))
    {
        // everything here is the same as your code

        if (!foundItem){
            m_items.emplace_back( item.clone(), 1 ); // create specialized type
                                                  // through clone
        }
    }
}
类项目{
//这里的其他同学。。。
公众:
虚拟std::shared_ptr clone()const=0;
};
阶级绷带{
公众:
std::shared_ptr clone()常量覆盖
{
return std::shared_ptr{new bandage{*this}};//使用bandage copy构造函数
//并实例化具体的项目类型
}
};
无效库存::附加项(常量项目和项目)
{
如果((m_items.size()
你能发布一个最小的可编译示例吗?不清楚哪里出了问题。试着将代码减少到两个类,基类和派生类,然后发布到这里。这可能与你的
addItem
函数有关。好的,我在帖子中展示了addItem函数。如果我通过const ref而不是指针,我是否会失去对派生信息的访问权限?否,v虚拟机制同样适用于参考资料。请参阅我更新的答案以了解(我认为)在哪里问题在于。除了答案中的内容之外,您的
std::vector m_items;
是错误的:即使将正确的类型分配给条目,也会将其切分为
InventoryItem
。实际上,您不能拥有~any派生类型~s的向量,编译器不知道如何分配。您需要做的是存储指针对他们来说——所有的结构指针都是相同的,因此指向bandage的指针可以正常工作,通过该指针访问其inventoryitem库当然也可以。您可能希望使其
虚拟
并使用协变返回类型(即
虚拟bandage*clone(){return new bandage(*this);}
虽然这里不严格要求协变返回类型。谢谢,我不知道可以像这样在重写的虚拟函数中更改返回类型。好的,所以我很快尝试了这个方法-它确实有效。但是我想我将尝试工厂方法,这样我将只拥有每种类型的派生项中的一个?@Petr,我想k这是唯一的例外(也适用于reference)