1

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.

IFeel3
  • 167
  • 1
  • 13

1 Answers1

3

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
    }
}
Community
  • 1
  • 1
SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
  • 1
    There is a minor difference in your approach if you'd for instance have a (norwegian forest cat)<-cat<-animal inheritance tree, the dynamic cast will succeed, but the typeids will obviously be different. – Lanting Nov 16 '16 at 09:36
  • @Lanting, yes, that is true, however it will still work for the OP in cases like "do something for all cats" or "do something for all norwegian forest cats (which are amazing animals, btw)", and that seems to be exactly what the OP wants to do. – SingerOfTheFall Nov 16 '16 at 09:40
  • I'm not familiar with smart pointers. If I have such vector then why can't I have a method like this: `void operator+=(Animal *arg) { vec.push_back(arg); } ` ? – IFeel3 Nov 16 '16 at 10:01
  • @IFeel3, you can, you just need pointers if you want polymorphism to work, doesn't matter whether they are smart pointers, or raw pointers. – SingerOfTheFall Nov 16 '16 at 10:02
  • @SingerOfTheFall Could you please tell me if I should know something about dealing with destruction of this vector? I wrote this code as you told me and it seems to work with one exception - after my code gets to the destructor of Herd it throws [this](https://i.snag.gy/QlHaUN.jpg). [Here's the code](http://pastebin.com/NZSw6pun) – IFeel3 Nov 16 '16 at 10:19
  • @IFeel3, if you use raw pointers, you should `delete` them manually. If you use smart pointers, you should not do anything at all, the memory will free itself. – SingerOfTheFall Nov 16 '16 at 10:43
  • @SingerOfTheFall I tried to write this method like this `Herd operator-(Animal *arg) { std::vector>::iterator position = vec.begin(); bool is_found = false; shared_ptr ptr(arg); while (position != vec.end() && !is_found) { if (typeid(arg) == typeid(position)){ vec.erase(position); is_found = true; } if (!is_found) position++; } return *this; }` but it doesn't work :/ – IFeel3 Nov 16 '16 at 11:23