IFeel3 IFeel3 - 20 days ago 6
C++ Question

Removing object from vector of base-class objects if matches specific class

I've created a simple class Animal which is base class for few different animals. Then I made another class called Herd which stores Animal type objects in vector and hold few methods operating on these objects.

class Herd {
public:

Herd() {}
~Herd() {}

Herd operator+(Animal arg) {
vec.push_back(arg);
return *this;
}

void operator+=(Animal arg) {
vec.push_back(arg);
}

Herd operator-(Animal arg) {
std::vector<Animal>::iterator position = std::find(vec.begin(), vec.end(), arg);
if (position != vec.end()) // == myVector.end() means the element was not found
vec.erase(position);
return *this;

}


void make_noise() {
vector<Animal>::iterator v = vec.begin();
while (v != vec.end()) {
v->give_sound();
v++;
}
cout << endl;
}

private:
vector<Animal> vec;
};


The problem is with deleting specific object from Vector. I overloaded operator- and I wanted it to take some Animal-derived class as a parameter and remove first occurrence of this class from vector: let's say vector contains Dog, Cat, Dog - then after calling herd-Cat I want it to be Dog, Dog. I would do this by iterating over my vector and find which element matches the arg object.

Unfortunately after passing Cat as the argument my class treats it as if it was Animal type so whatever I pass to the function, the first element is always deleted.

I tried to achieve this by making a vector of pointers, not objects but then again my whole program covers with errors of which I have no idea how to fix to make this whole thing work.

Answer

In this case you are going to experience object slicing. In order to make it work, you will have to use pointers. It is a good idea, however, to store std::shared_ptr or std::unique_ptr in the vector instead of raw pointers, because in this case you will not have to free the memory yourself.

Finally, to check the exact type you could try to dynamic_cast the pointer, or check it's typeid. Alternatively, you could also create a polymorphic type() function and override it in each derived class to return it's exact type, but that will probably be an overkill in this case.

vector<shared_ptr<Animal>> vec;

for(auto animal : vec)
{
    if(dynamic_cast<Cat*>(animal.get()))
    {
        //cat
    }
    if(typeid(*animal) == typeid(Cat))
    {
        //also a cat
    }
}
Comments