首页 > 解决方案 > std::find 返回一个我无法访问函数的类

问题描述

我来自 C/C# 语言,现在我正在尝试学习 C++ 和他的标准函数。

现在,我正在创建一个名为IMonsterDead. 我将有一个std::vector<IMonsterDead*>怪物N

例子:

class IMonsterDead {
public:
    IMonsterDead(int Id)
    {
        this->_Id = Id;
    }

    virtual void OnDead() = 0;

    int Id() const {
        return _Id;
    }
private:
    int _Id;
};

一个实现该类的类:

class MonsterTest : public IMonsterDead {
public:
    MonsterTest(int generId)
        : IMonsterDead(generId)
    {
    }

    virtual void OnDead()
    {
        std::cout << "MonsterTesd died" << std::endl;
    }
};

好的,如果我直接访问一切正常。但我正在尝试使用std::find.

完整程序测试:

int main()
{
    std::vector<IMonsterDead*> monsters;
    for (int i = 0; i < 1000; i++)
    {
        monsters.emplace_back(new MonsterTest(1000 + i));
    }

    int id = 1033;
    std::vector<IMonsterDead*>::iterator result = std::find(monsters.begin(), monsters.end(), [id]( IMonsterDead const* l) {
        return l->Id() == id;
    });

    if (result == monsters.end())
        std::cout << "Not found" << std::endl;
    else
    {
         // Here I want to access OnDead function from result
    }

    return 0;
}

所以我需要访问OnDead功能,result但我不能。Intellisense 没有为我显示任何内容。结果存在。

如何访问该功能?还有另一种更好的方法吗?

标签: c++vector

解决方案


您需要使用std::find_if()而不是std::find(). std::find()用于查找具有特定值的元素,因此您必须将实际值传递给它才能找到,而不是用户定义的谓词。 std::find_if()用于根据谓词查找元素。

无论哪种方式,如果找到匹配项,取消引用返回的迭代器会给你一个IMonsterDead*指针(更准确地说,它会给你一个IMonsterDead*&指向指针的引用)。然后,您需要取消引用该指针才能访问任何成员,例如OnDead().

你也在泄漏内存。你不是delete你的对象new。在处理通过指向基类的指针删除的多态类型时,基类需要一个virtual析构函数来确保正确调用所有派生析构函数。

话虽如此,您显然正在使用 C++11 或更高版本(事实上您正在使用vector::emplace_back()),因此您应该使用 C++11 功能来帮助您更好地管理代码:

  • 你应该用它std::unique_ptr来包装你的怪物对象,这样你就不需要delete手动处理它们了。

  • 在覆盖虚拟方法时,您应该始终使用override关键字,以确保正确覆盖它。编译器在使用时override比不使用时可以捕获更多的语法错误。

  • auto每当您声明编译器可以为您推断其类型的变量时,您都应该使用它。在处理模板化代码时特别有用。

尝试更多类似的东西:

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>

class IMonsterDead {
public:
    IMonsterDead(int Id)
        : m_Id(Id)
    {
    }

    virtual ~IMonsterDead() {}

    virtual void OnDead() = 0;

    int Id() const {
        return m_Id;
    }

private:
    int m_Id;
};

class MonsterTest : public IMonsterDead {
public:
    MonsterTest(int generId)
        : IMonsterDead(generId)
    {
    }

    void OnDead() override
    {
        std::cout << "MonsterTest died" << std::endl;
    }
};

int main()
{
    std::vector<std::unique_ptr<IMonsterDead>> monsters;
    for (int i = 0; i < 1000; i++)
    {
        // using emplace_back() with a raw pointer risks leaking memory
        // if the emplacement fails, so push a fully-constructed
        // std::unique_ptr instead, to maintain ownership at all times...
        monsters.push_back(std::unique_ptr<IMonsterDead>(new MonsterTest(1000 + i)));

        // or:
        // std::unique_ptr<IMonsterDead> monster(new MonsterTest(1000 + i));
        // monsters.push_back(std::move(monster));

        // or, if you are using C++14 or later:
        // monsters.push_back(std::make_unique<MonsterTest>(1000 + i));
    }

    int id = 1033;
    auto result = std::find_if(monsters.begin(), monsters.end(),
        [id](decltype(monsters)::value_type &l) // or: (decltype(*monsters.begin()) l)
        {
            return (l->Id() == id);
        }

        // or, if you are using C++14 or later:
        // [id](auto &l) { return (l->Id() == id); }
    );

    if (result == monsters.end())
        std::cout << "Not found" << std::endl;
    else
    {
        auto &monster = *result; // monster is 'std::unique_ptr<IMonsterDead>&'
        monster->OnDead();
    }

    return 0;
}

推荐阅读