4

So I've got a simple task to do. There are 3 classes derived from one base class. They're quite simple and will be provided below. What I need to do is create a new class called PolymorphicAnimal, that'll be able to behave just as any other animal derived from the Animal base class. To be exact, all they need to do is display the right text after method SoundOff is called. I'm guessing I need to use dynamic_cast here. My question is, what's the right syntax for using dynamic_cast as an if statement, and do all the derived classes need to have at least one virtual method as well?

#include "stdafx.h"
#include <iostream>
#include <string>

class Animal {
public:
virtual std::string SoundOff() = 0;
};

class Dog : public Animal {
std::string SoundOff() override { return "Woof"; }
};

class Cat : public Animal {
std::string SoundOff() override { return "Meow"; }
};

class Cow : public Animal {
std::string SoundOff() override { return "Muu"; }
};

class PolymorphicAnimal : public Animal {
std::string sound;
public:
PolymorphicAnimal(const Animal &a) {
    if(std::dynamic_cast<Cat*>(a))
}
};

The line if(std::dynamic_cast... generates compiler errors:

syntax error '<', illegal token on the right side of :: and expected an identifier

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
Melvin Brooks
  • 73
  • 1
  • 6

4 Answers4

9

In C++ you can declare a variable in the conditional of an if, which is a powerful feature that you can exploit here. So,

if (auto kitty = dynamic_cast<const Cat*>(&a)){
    // kitty is not nullptr
}

Notes:

  1. dynamic_cast is a keyword; do drop the std::
  2. I've used a pointer dynamic_cast. The reference alternative is impractical as you can't, in general, expect an implicit conversion of a reference type to a bool type, and if a reference cast fails an exception is thrown.
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
5

dynamic_cast is almost always a hack.

Why don't you add another virtual method to Animal, and then have Dog, Cat and Cow override it in the usual way? Or don't you control these classes?

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
  • This is a task that usually comes on my exam and carries a nice amount of points for what it is, and the professor expects as to show that we know when and how to use `dynamic_cast` – Melvin Brooks Jul 03 '18 at 09:37
  • 1
    OK, well, if you have no choice... So now you know how, and the 'when' is ... 'never' :) – Paul Sanders Jul 03 '18 at 09:39
  • ͏+͏1͏͏͏͏͏͏͏͏͏͏͏͏͏ Nothing wrong with curve-ball answers if they contain excellent advice, which this one does. – Bathsheba Jul 03 '18 at 09:44
  • @Bathsheba Thanks, I'm honoured. Curve-ball answers are a bit of a trademark of mine. Doesn't always work, but, well, you know. – Paul Sanders Jul 03 '18 at 09:56
  • And you can of course now easily add classes `Badger`, `Gerbil` and `Weasel`. – Paul Sanders Jul 15 '18 at 10:48
0

Whereas virtual methods or visitor might be more appropriated, you might use something like:

PolymorphicAnimal(const Animal &a) {
    if (const auto* cat = dynamic_cast<const Cat*>(&a)) {
        // use cat
    } else if (const auto* dog = dynamic_cast<const Dog*>(&a)) {
        // use dog
    } // ...
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

It is very unclear what exactly the PolymorphicAnimal should do. Somehow you need to tell PolymorphicAnimal how to behave, right? So, I'm guessing it's more like a Factory than a derived class.

Something like this:

class PolymorphicAnimal : Animal
{
private:
    Animal *animal;
public:
    PolymorphicAnimal(int type)
    {
        if (type == Type_Cat) // Type_Cat is an enum for example
        {
            animal = new Cat();
        }
        // ...add other types here
    }
    std::string SoundOff()
    {
        return animal->SoundOff();
    }
}

Normally, you shouldn't need to do if (something dynamic_cast something) in a normal program.

AndreiM
  • 815
  • 9
  • 17