2

I am iterating through a list of Animal objects (which contains 3 or 4 different types of objects all subclassing from Animal):

foreach (Animal entry, animalList)
{

    switch(entry.animalType)
    {
    case Animal::tiger:
        qDebug() << static_cast<Tiger>(entry).tigerString;
        break;
    }
}

This gives me the following error:

no matching function for call to 'Tiger::Tiger(Animal&)'

So I tried:

static_cast<Tiger*>(entry).tigerString;

Which gives me the following error:

invalid static_cast from type 'Animal' to type 'Tiger*'

So finally I decided to change entry to a pointer type like so:

foreach (Animal* entry, animalList) etc....

And I get the following error:

cannot convert 'const value_type {aka const Animal}' to 'Animal*' in initialization

Am I missing something here? I absolutely need to get tigerString which is a string specific to the subclass Tiger.

What should I be doing?

UPDATE Please see the following (the code has been stripped for cleanliness):

std::list<Animal*> animalList;

Tiger *myTiger = new Tiger();
myTiger->animalType= Animal::tiger;
myTiger->tigerString= "I am a tiger";

animalList.push_back(myTiger, animalList);

foreach (Animal* entry, animalList)
{
    Tiger* tiger = dynamic_cast <Tiger*> (entry);

    if (tiger)
    {
        // It is a tiger
    }
    else
    {
        // it is NOT a tiger
     }
}

I get the following error at the first line in the foreach loop:

cannot dynamic_cast 'animal' (of type 'class Animal*') to type 'class Tiger*' (source type is not polymorphic)

PaulG
  • 6,920
  • 12
  • 54
  • 98
  • static_cast(&entry)->tigerString ? – ChronoTrigger Jul 18 '13 at 14:19
  • 8
    Be careful, if you are passing `entry` by value, it will _never_ be anything else than a plain `Animal`. – Nbr44 Jul 18 '13 at 14:21
  • @ChronoTrigger Got the code to compile and run but it crashes my app. – PaulG Jul 18 '13 at 14:23
  • @Nbr44 it won't make a difference if they really have list of `Animal` objects. – juanchopanza Jul 18 '13 at 14:26
  • why static_cast used, not dynamic_cast for downcasting? – Sergei Nikulov Jul 18 '13 at 14:26
  • 1
    @Sergey: Because the code is wrong. – John Dibling Jul 18 '13 at 14:27
  • `foreach`??? What's that, a macro? – robson3.14 Jul 18 '13 at 14:32
  • In addition to the slicing and pass-by-value issues already noted, perhaps your `Animal` is (was) actually an `Alligator`, not a `Tiger`... – twalberg Jul 18 '13 at 14:33
  • @John Dibling Yes the code is indeed wrong and I was not able to compile. This is why I need help – PaulG Jul 18 '13 at 14:34
  • What is this `foreach` you are using? That doesn't look like `std::foreach`. In general, that doesn't look like actual C++ code. Post *actual code* when you cannot get something to compile. Delete parts of that *actual code* that are not important, until you have a code sample that is short, self contained, and gets exactly the error you are confused about when you compile it. http://sscce.org – Yakk - Adam Nevraumont Jul 18 '13 at 14:36
  • @PaulG: And that is why I am trying to help you. :) – John Dibling Jul 18 '13 at 14:42
  • May I suggest you add add a pure virtual function to the base class called "AnimalString()" or some such and then each derived type returns its own string? Then you won't even need the casting and can just loop through the base types and call AnimalString() on them. – paulm Jul 18 '13 at 14:53

1 Answers1

8

Your function takes an Animal by-value, rather than by-reference or pointer. I'm guessing you have a polymorphic hierarchy designed where Animal is the ABC and Tiger is a concrete derived class.

If so, this code is certianly wrong. By taking the Animal by value, you slice the object, and all you're left with is just an Animal. All the Tigerness is gone.

When you did

static_cast<Tiger*>(entry).tigerString;

You were trying to cast a non-pointer to a pointer. That will never work. Change your function to take a Animal by reference (or pointer).

You are also trying to use the wrong cast. You should be using dynamic_cast, not static_cast here, when going from a base to a derived polymorphic object.

Do this:

foreach (Animal* animal)
{
  Tiger* tiger = dynamic_cast <Tiger*> (animal);
  if (tiger)
  {
    // It is a tiger
  }
  else
  {
    // it is NOT a tiger
  }
}

Finally, from the comments it was discovered that you were not actually using polymorphic types. A polymorphic class is one which has at least one virtual member function in the base class. One of those virtual member functions should be the destructor in most cases1:

class Animal
{
public:
  virtual ~Animal(){};
};

...Even if it is trivial (no implementation). In many cases this might even be the only virtual member function, and that's fine.


1 "One of those virtual member functions should be the destructor in most cases" : This is needed when you will delete an instantiation of the derived class via a pointer to the base class, as with:

class Animal
{
public:
  virtual ~Animal() {}
};

class Tiger : public Animal
{
};

int main()
{
  Animal* a = new Tiger;
  delete a; // Without the virtual destructor, this would evoke Undefined Behavior
}

Rule Of Thumb: When in doubt, add a virtual destructor to all polymorphic base classes.

Community
  • 1
  • 1
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • OP claims they have a list of `Animal` objects (they could be wrong, of course). If that is true then passing by reference isn't going to give them much joy. – juanchopanza Jul 18 '13 at 14:34
  • @juanchopanza: Um, yeah you're probably right. But there is *sooo* much going wrong here, and I had to start somewhere. – John Dibling Jul 18 '13 at 14:41
  • 1
    @PaulG: The compiler error tells you *exactly* what the problem is: "cannot dynamic_cast 'animal' (of type 'class Animal*') to type 'class Tiger*' (**source type is not polymorphic**)" You need to make `Animal` polymorphic. – John Dibling Jul 18 '13 at 14:45
  • @John Dibling You were absolutely right, just had to add a virtual method to my Animal class, which is weird because the method does nothing and I don't really need a method in my Animal class. – PaulG Jul 18 '13 at 15:00
  • 1
    @PaulG: Be sure that `Animal` has a `virtual` destructor. In fact, in many polymorphic hierarchies the only method that is `virtual` is the dtor. Also, I would strongly suggest checking out our list of recommended books. You'll probably get a lot of traction from some of them. – John Dibling Jul 18 '13 at 15:02
  • Thanks John, actually c++ was the first language I ever learned to program in, but that was years ago and I've only started using it again recently. I've got some good books at home, maybe a little outdated but the fundamentals are there. I remember it took me a few months to wrap my head around pointers, fond memories. Truth is I'm under heavy time constraints and have little time to go over the material, I'm more of a c# expert than anything else. – PaulG Jul 18 '13 at 15:11