Home > Blockchain >  How can I get the object of specific type from vector that contains multiple type of objects
How can I get the object of specific type from vector that contains multiple type of objects

Time:10-08

I've got a question, if we have a class A and other classes from class B : class A to class Z : class A are inherited from class A, and we have a vectorstd::vector<A> that contains objects of all types from class A to class Z, how can we get an object of specific type from that vector, for example we want to get object which is type of E how to get that object.

class A {};
class B : A {};
class C : A {};
...
class Z : A {};

std::vector<A> vec; // lets say it contains objects of type A to Z

template<typename T>
T GetObject()
{
    for (int i = 0; i < vec.size(); i  )
    {
        //if type of vec[i] == type of T return vec[i]
    }
}

E obj = GetObject<E>();

I've used something like this

if (typeid(vec[i]) == typeid(T))
{
    return vec[i];
}

but it doesn't work.

CodePudding user response:

You cannot store subtypes of A in a std::vector<A>. Any objects of a subtype you put in there are sliced and every element in the vector is simply an object of type A.

You could use a std::vector<std::variant<A, ..., Z>> instead. You should probably think about a different design though:

#define TYPES(x) \
    x(B)    \
    x(C)    \
    x(D)    \
    x(E)    \
    x(F)    \
    x(G)    \
    x(H)    \
    x(I)    \
    x(J)    \
    x(K)    \
    x(L)    \
    x(M)    \
    x(N)    \
    x(O)    \
    x(P)    \
    x(Q)    \
    x(R)    \
    x(S)    \
    x(T)    \
    x(U)    \
    x(V)    \
    x(W)    \
    x(X)    \
    x(Y)    \
    x(Z)

#define DECLARE(x) struct x { void operator()() {std::cout << #x << '\n'; } };

#define EMPLACE(x) data.emplace_back(x{});
#define TYPE_PARAMS(x) ,x


DECLARE(A);
TYPES(DECLARE);

using Variant = std::variant<A TYPES(TYPE_PARAMS)>;

int main() {
    std::vector<Variant> data;

    EMPLACE(A);
    TYPES(EMPLACE);

    using SearchedType = E;

    auto pos = std::find_if(data.begin(), data.end(), [](Variant const& v) { return std::holds_alternative<SearchedType>(v); });

    if (pos != data.end())
    {
        std::visit([](auto& v) { v(); }, *pos);
    }
}

An alternative would be to declare a template variable:

template<class T>
T object{};

int main() {
    using SearchedType = E;

    object<SearchedType>();
}

Another option would be to add a virtual destructor to A and use a std::vector<std::unique_ptr<A>> combined with dynamic_cast...

  • Related