Удаление элемента из вектора по типу

/ Просмотров: 701

Бывает ситуация, когда есть базовый класс Base и его наследники Derived1 и Derived2 и есть вектор, который хранит элементы типа Base*. Может возникнуть ситуация, когда надо удалить из этого вектора все элементы, которые относятся только к определённому типу. Сегодня я расскажу, как это сделать. Объявим наши классы.

class Base
{
public:
    virtual void sayHello()
    {
        cout << "Hello from Base";
    }
};

class Derived1 : public Base
{
public:
    virtual void sayHello()
    {
        cout << "Hello from Derived1";
    }
};

class Derived2 : public Base
{
public:
    virtual void sayHello()
    {
        cout << "Hello from Derived2";
    }
};

И напишем функцию main, которая заполнит вектор данными и выведет содержимое этого вектора.

vector<Base*> elements;
int main()
{
    elements.push_back(new Derived1);
    elements.push_back(new Derived2);
    elements.push_back(new Derived2);
    elements.push_back(new Derived1);

    for (Base* element : elements)
    {
        element->sayHello();
    }

    for (Base* element : elements)
    {
        delete element;
    }
    elements.clear();
    return 0;
}

И напишем функцию main, которая заполнит вектор данными и выведет содержимое этого вектора.

vector<Base*> elements;
int main()
{
    elements.push_back(new Derived1);
    elements.push_back(new Derived2);
    elements.push_back(new Derived2);
    elements.push_back(new Derived1);

    for (Base* element : elements)
    {
        element->sayHello();
    }

    for (Base* element : elements)
    {
        delete element;
    }
    elements.clear();
    return 0;
}

Насколько мне известно, в C++ принимать тип как параметр могут только шаблоны функций. Поэтому давайте напишем шаблон, параметром которого будет тип, подлежащий удалению.

template <class T>
void deleteByType()
{
    for (int i = 0; i < elements.size(); i++)
    {
        T* a = dynamic_cast<T*>(elements[i]);
        if (a != nullptr)
        {
            delete a;
            elements.erase(elements.begin() + i);
            cout << i << "th element deleted";
            i--;
        }
    }
}

В этой функции перебираются все элементы вектора и делается попытка привести каждый элемент к данному типу. В случае успешного преобразования функция dynamic_cast возвращает преобразованный элемент, и тогда его можно удалять из вектора. Если преобразование не удалось, то dynamic_cast возвращает nullptr, и тогда удалять ничего не нужно. Всё просто! Однако у этого метода есть ограничения: в шаблон нельзя передавать левые параметры, которые не имеют никакого отношения к типу Base, например, int. Это вызовет ошибку компиляции. А теперь давайте воспользуемся нашей функцией и удалим какие-нибудь элементы.

deleteByType<Derived1>(); //Удалит первый и последний элемент
deleteByType<Derived2>(); //Удалит элементы посередине
deleteByType<Base>(); //Удалит все элементы

Полностью код может выглядеть так:

#include <vector>
#include <iostream>

using namespace std;

class Base
{
public:
    virtual void sayHello()
    {
        cout << "Hello from Base";
    }
};
class Derived1 : public Base
{
public:
    virtual void sayHello()
    {
        cout << "Hello from Derived1";
    }
};
class Derived2 : public Base
{
public:
    virtual void sayHello()
    {
        cout << "Hello from Derived2";
    }
};
vector<Base*> elements;

template <class T>
void deleteByType()
{
    for (int i = 0; i < elements.size(); i++)
    {
        T* a = dynamic_cast<T*>(elements[i]);
        if (a != nullptr)
        {
            delete a;
            elements.erase(elements.begin() + i);
            cout << i << "th element deleted";
            i--;
        }
    }
}

int main()
{
    elements.push_back(new Derived1);
    elements.push_back(new Derived2);
    elements.push_back(new Derived2);
    elements.push_back(new Derived1);

    for (Base* element : elements)
    {
        element->sayHello();
    }

    deleteByType<Derived1>();

    for (Base* element : elements)
    {
        element->sayHello();
    }     

    for (Base* element : elements)
    {
        delete element;
    }
    elements.clear();
    return 0;
}

Результат выполнения кода смотрите по ссылке

Комментариев: 1 RSS

Оставьте комментарий!

Комментарий будет опубликован после проверки

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

(обязательно)