I'm trying to set up a simple case to solve a textbook exercise. The code is on IDEone, and repeated below.
The code is a simplified case of trying to store a number of lists of animals, and being able to return any generic animal from one of these animal-specific lists held inside my wrapper queue.
I can add animals just fine and when trying to retrieve a dog, I appear to get a pointer to the dog since I can print its name
. However, if I try to call its member function speak()
, the code crashes and I can't figure out why.
class Animal {
public:
virtual void speak() = 0;
string name;
};
class Dog: public Animal {
public:
Dog(string n) { this->name=n; }
void speak() { cout<<name<<" says WOOF!"<<endl; }
};
class AnimalQueue {
list<Dog> dogs;
list<Cat> cats; // etc.
public:
void enqueue(Animal* a) {
Dog * d = dynamic_cast<Dog*>(a);
if (d!=nullptr) dogs.push_back(*d);
else // check for other animals, etc.
}
Dog* dequeueDog() {
Dog * d = &(dogs.front());
dogs.pop_front();
return d;
}
Animal dequeueAny() {
// Should return a random animal from any list
}
};
int main() {
// Set up
AnimalQueue q;
Dog * d;
d = new Dog("Rex");
q.enqueue(d);
// Retrieve Rex
d = q.dequeueDog();
cout<<d->name<<endl; // Prints "Rex"
d->speak(); // Crashes?!
return 0;
}
EDIT: Sorry, in cutting down my code, I eliminated the essence of the problem, which is that I should be able to add any sub-class of Animal
to my list, and there's a special function called dequeueAny()
which should be able to return a random Animal
from any list. The code has been edited to include this (as well as my previously omitted nullptr
checks when enqueue
ing.
What's the best way to handle this? Is it to pass in a reference to an existing Animal
object? Would that work? ie could, I have:
void dequeueAny(Animal * a) {
// for example, let's return a Dog
Dog d = dogs.front();
dogs.pop_front();
*a = d;
}
Admittedly, things like dequeueDog()
should probably return a Dog
by value.