std :: find возвращает класс, который я не могу получить доступ к функциям - PullRequest
0 голосов
/ 03 декабря 2018

Я пришел из языка 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 ничего не показывает для меня.Результат существует.

Как я могу получить доступ к этой функции?Есть еще лучший способ сделать это?

Ответы [ 2 ]

0 голосов
/ 03 декабря 2018

Вам нужно использовать std::find_if() вместо std::find().std::find() предназначен для поиска элемента с определенным значением, поэтому вы должны передать ему фактическое значение для поиска, а не предикат user_defined.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;
}
0 голосов
/ 03 декабря 2018

Итераторы - это интересная абстракция, которая в данном случае сводится к указателям.

Либо вы получаете указатель на элемент, либо вы получаете неверный конец.

Вы можете использовать его какуказатель: (*result)->func();

Вы также можете использовать его для создания новой переменной:

IMonsterDead &m = **result; 
m.func();

Это должно дать одинаковую сборку, обе возможны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...