0

Classes Dog and Cat derive from Animal, which in turn derives from Creature. Also pDog, pCat, pAnimal, and pCreature are pointers to their class. Animal and Creature are both abstract classes.

What is wrong with my code?

pAnimal = new Dog();
pDog = pAnimal;
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
jake craigslist
  • 303
  • 3
  • 12

4 Answers4

4

You can convert up a hierarchy (i.e., from derived to base) implicitly.

Converting down the hierarchy (from base to derived) has to be done explicitly. In most cases, you want to use dynamic_cast so the conversion will only succeed if correct:

Animal *pAnimal = new Dog();

Dog *pDog = dynamic_cast<Dog *>(pAnimal);

Note that your classes need to contain at least one virtual function for this to work (but if you don't have virtual functions, the hierarchy probably doesn't make sense at all).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
4

I'm assuming pAnimal is of type Animal* and pDog is of type Dog*.

When you assign the new Dog() to pAnimal, it casts the Dog* to an Animal* which is perfectly legal, since Dog derives from Animal.

Going back the other way (i.e. casting from Animal* to Dog*) is different however. Since there are situations where this would be an invalid cast (i.e. if pAnimal pointed to a Cat), the compiler requires that you explicitly cast it, for example:

pDog = static_cast<Dog*>(pAnimal);

You will want to use dynamic_cast if you aren't sure of the type, for example:

pDog = dynamic_cast<Dog*>(pAnimal);

if (!pDog)
{
    // invalid cast, pAnimal didn't point to a Dog
}

dynamic_cast will check if the cast is valid, and if not it will return a null pointer.

Edit: using static_cast may give a slight performance gain over dynamic_cast, however should only be used if you are 110% sure of the type.

brettwhiteman
  • 4,210
  • 2
  • 29
  • 38
  • You don't *need* to use `dynamic_cast`, but you risk undefined behavior if you use any other style of cast. – Mark Ransom Jul 16 '15 at 23:18
  • 1
    `dynamic_cast` only works if `Animal` has at least one virtual function. If you don't have any so far, making the destructor virtual is a good choice – M.M Jul 17 '15 at 00:34
0

You are hoping that the compiler will remember that a Dog is always the type pointed to in your code.

In general, you can't assign any old Animal * to a Dog *.

In your specific case, C++ will follow the same general rule. The compiler will not scan your code to see if pDog = pAnimal; might be allowable.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
0

Guessing that pAnimal is Animal* and pDog is Dog*, then you have a type mistmatch caused by the fact that an Animal* is not convertible to Dog* indipendently from the dynamic type of the object.

You can:

  • downcast via static_cast if you are sure about the dynamic type of the object pointed to
  • downcast via dynamic_cast if you are not sure
Shoe
  • 74,840
  • 36
  • 166
  • 272
  • `static_cast` only works if the base is non-virtual. – Kerrek SB Jul 16 '15 at 23:23
  • @πάνταῥεῖ: How can you statically know the containing object if it is only determined at runtime? – Kerrek SB Jul 16 '15 at 23:36
  • @KerrekSB _" How can you statically know the containing object if it is only determined at runtime?"_ I didn't meant exclusively determined at runtime (e.g. using a CRTP). Anyway `static_cast<>` works for virtual and non virtual classes, may be your wording is a bit misleading. – πάντα ῥεῖ Jul 16 '15 at 23:41
  • @KerrekSB That clarified a lot. I was mistaking `virtual` base for base class with `virtual` function. – πάντα ῥεῖ Jul 16 '15 at 23:51
  • @πάνταῥεῖ: No. That's a *polymorphic class*, as opposed to a *virtual base*. A derived class with a virtual base is always polymorphic, though. – Kerrek SB Jul 16 '15 at 23:53
  • @πάνταῥεῖ: The unifying theme is of course that "virtual" means "determined at runtime". – Kerrek SB Jul 16 '15 at 23:55