first off: I have read and I know now that a virtual template member function is not (yet?) possible in C++. A workaround would be to make the class a template and then use
I have copied your code and modified it, so now it should work exactly as you want:
#include
#include
//defined new enum type
enum AnimalEnum
{
animal,
wolf,
fish,
goldfish,
other
};
//forward declarations
class Wolf;
class Fish;
class GoldFish;
class OtherAnimal;
class Animal {
private:
AnimalEnum who_really_am_I;
void* animal_ptr;
public:
//declared new constructors overloads for each type of animal
Animal(const Animal&);
Animal(const Wolf&);
Animal(const Fish&);
Animal(const GoldFish&);
Animal(const OtherAnimal&);
template< class AMOUNT >
/*removed the virtual keyword*/ void eat( AMOUNT amount ) const {
switch (this->who_really_am_I)
{
case AnimalEnum::other: //You defined OtherAnimal so that it doesn't override the eat action, so it will uses it's Animal's eat
case AnimalEnum::animal: std::cout << "I eat like a generic Animal." << std::endl; break;
case AnimalEnum::wolf: ((Wolf*)this->animal_ptr)->eat(amount); break;
case AnimalEnum::fish: ((Fish*)this->animal_ptr)->eat(amount); break;
case AnimalEnum::goldfish: ((GoldFish*)this->animal_ptr)->eat(amount) break;
}
}
void DeleteMemory() { delete this->animal_ptr; }
virtual ~Animal() {
//there you can choose if whether or not to delete "animal_ptr" here if you want or not
}
};
class Wolf : public Animal {
public:
template< class AMOUNT >
void eat( AMOUNT amount) const {
std::cout << "I eat like a wolf!" << std::endl;
}
virtual ~Wolf() {
}
};
class Fish : public Animal {
public:
template< class AMOUNT >
void eat( AMOUNT amount) const {
std::cout << "I eat like a fish!" << std::endl;
}
virtual ~Fish() {
}
};
class GoldFish : public Fish {
public:
template< class AMOUNT >
void eat( AMOUNT amount) const {
std::cout << "I eat like a goldfish!" << std::endl;
}
virtual ~GoldFish() {
}
};
class OtherAnimal : public Animal {
//OtherAnimal constructors must be defined here as Animal's constructors
OtherAnimal(const Animal& a) : Animal(a) {}
OtherAnimal(const Wolf& w) : Animal(w) {}
OtherAnimal(const Fish& f) : Animal(f) {}
OtherAnimal(const GoldFish& g) : Animal(g) {}
OtherAnimal(const OtherAnimal& o) : Animal(o) {}
virtual ~OtherAnimal() {
}
};
//OtherAnimal will be useful only if it has it's own actions and members, because if not, typedef Animal OtherAnimal or using OtherAnimal = Animal can be used, and it can be removed from above declarations and below definitions
//Here are the definitions of Animal constructors that were declared above/before:
Animal::Animal(const Animal& a) : who_really_am_I(AnimalEnum::animal), animal_ptr(nullptr) {}
Animal::Animal(const Wolf& w) : who_really_am_I(AnimalEnum::wolf), animal_ptr(new Wolf(w)) {}
Animal::Animal(const Fish& f) : who_really_am_I(AnimalEnum::fish), animal_ptr(new Fish(f)) {}
Animal::Animal(const GoldFish& g) : who_really_am_I(AnimalEnum::goldfish), animal_ptr(new GoldFish(g)) {}
Animal::Animal(const OtherAnimal& o) :
who_really_am_I(AnimalEnum::other), animal_ptr(new OtherAnimal(o)) {}
int main() {
std::vector animals;
animals.push_back(Animal());
animals.push_back(Wolf()); //Wolf is converted to Animal via constructor
animals.push_back(Fish()); //Fish is converted to Animal via constructor
animals.push_back(GoldFish()); //GoldFish is converted to Animal via constructor
animals.push_back(OtherAnimal()); //OtherAnimal is converted to Animal via constructor
for (std::vector::const_iterator it = animals.begin(); it != animals.end(); ++it) {
it->eat(); //this is Animal's eat that invokes other animals eat
//delete *it; Now it should be:
it->DeleteMemory();
}
animals.clear(); //All animals have been killed, and we don't want full vector of dead animals.
return 0;
}