【问题标题】:How do you check if a derived class object is already being stored in a vector?如何检查派生类对象是否已存储在向量中?
【发布时间】:2017-10-12 00:00:29
【问题描述】:

我正在尝试为基于文本的游戏创建库存系统。我目前正在研究将派生自名为 Items 的类的对象添加到向量的函数,然后从派生类调用函数以更新其数量。我可以很容易地做到这一点,但我想在函数中添加一些检查,这样它不会将重复对象添加到向量中,而是会找到重复对象并调用其函数来更新其数量。

我试过这样做,但是当程序被删除时,程序会崩溃。所以我决定尝试删除 delete 并且能够调用函数 showInventory() 并得到非常奇怪的结果。

我试图弄清楚如何检查一个类对象是否已经存储在一个向量中,以及它是否返回向量中的元素位置,以便我可以使用对象 addQuant() 函数,以便我可以更新它数量

std::vector<Items*> inv;

void Inventory::AddtoInv( Items* s)
{
    if (!inv.empty())
    {
        for (int i = 0; i < inv.size(); i++)
        {
            if (inv[i]->getName() == s->getName())
            {
                inv[i]->addQuant();
                delete s;
            }
            else
            {
                s->addQuant();
                inv.push_back(s);
            }
        }
    }
    else{
        s->addQuant();
        inv.push_back(s);
    }
}

void Inventory::ShowInv()
{
    std::cout << "your inventory" << std::endl;
    for (unsigned int i = 0;i < inv.size(); i++)
    {
        std::cout << i << ": " << inv[i]->getName() << "    x" << inv[i]->showQuant() << std::endl;
    }
}

我也试过了,但是 std::find() 没有找到对象。

if (std::find(inv.begin(), inv.end(), s) != inv.end())
{

    std::cout << "you already have this item" << std::endl;
}
else
{
    inv.push_back(s);
    std::cout << "added item: " << s->getName << std::endl;
}

【问题讨论】:

  • 您有一个指针向量,因此std::find(inv.begin(), inv.end(), s) 的默认行为将是比较指针。如果地址不同,则说明您没有相同的实例,无论指针处对象的内容多么相似,它们都不会匹配。这使得这个问题与std::find() on a vector of pointers 重复
  • 调用AddtoInv()的代码是什么样的?
  • 如果inv 已经包含四个指针并且s 与第三个元素同名,请向您的橡皮鸭解释AddtoInv 中会发生什么。
  • @RemyLebeau 用于一个案例,所以案例 1:inv.AddtoInv(new Grain) 它传入了 Items 类的子类。
  • 在这样的函数参数中直接使用new 是不好的做法。如果AddtoInv() 抛出异常(如inv.push_back()),那么您就会泄漏内存。在这种情况下,请考虑将std::unique_ptr&lt;Items&gt; 用于AddtoInv() 参数,将std::vector&lt;std::unique_ptr&lt;Items&gt;&gt; 用于inv。这样一来,谁拥有什么就毫无疑问了。当inv 被清除或销毁时,您可以自动销毁库存物品,因此您不必手动进行

标签: c++ object search vector polymorphism


【解决方案1】:

您的AddtoInv() 函数可以简化为:

Items* Inventory::GetfromInv(const string &name)
{
    for (int i = 0; i < inv.size(); ++i)
    {
        if (inv[i]->getName() == name)
            return inv[i];
    }

    /* alternatively:

    auto iter = std::find_if(inv.begin(), inv.end(), [&](Items *item){ return (item->getName() == name); });
    if (iter != inv.end())
        return *iter;
    */

    return 0;
}

void Inventory::AddtoInv( Items* s)
{
    Items *item = GetfromInv(s->getName());
    if (!item)
    {
        inv.push_back(s);
        item = s;
    }
    else
        delete s;

    item->addQuant();
}

话虽如此,delete 上的崩溃以及showInv() 上的奇怪结果意味着您没有正确管理指针。例如,如果您正在销毁 inv 向量所指向的静止对象。但是您没有显示任何调用 AddInv() 或以其他方式使用库存的代码,因此我们无法帮助您诊断您在该代码中可能遇到的任何问题。

【讨论】:

  • 感谢您的完美工作!有人建议使用 std::find_if,与 find_if 相比使用它有什么优点或缺点,反之亦然?
  • std::find_if()find_if() 是同一个函数。仅当您有 using namespace std; 语句(您不应该使用)或 using std::find_if; 语句时,后者才会编译
  • 我的意思是在您发布的代码上使用 find_if 的优点或缺点?
  • std::find_if() 是 STL 中的标准化算法,为什么要重复已经为您完成的相同工作?
猜你喜欢
  • 2018-09-17
  • 1970-01-01
  • 2012-07-03
  • 2013-03-27
  • 2012-02-05
  • 1970-01-01
  • 2012-09-06
相关资源
最近更新 更多