I'm trying to understand dynamic type casting. How to properly implement the DrawAnimals and Talk To Animals functions using dynamic_cast?
DrawAnimals draws animals that can be drawn. Such animals implement the Drawable interface. TalkToAnimals conducts a conversation with animals that can talk, that is, they implement the Speakable interface.
class Speakable {
public:
virtual ~Speakable() = default;
virtual void Speak(ostream& out) const = 0;
};
class Drawable {
public:
virtual ~Drawable() = default;
virtual void Draw(ostream& out) const = 0;
};
class Animal {
public:
virtual ~Animal() = default;
void Eat(string_view food) {
cout << GetType() << " is eating "sv << food << endl;
energy_;
}
virtual string GetType() const = 0;
private:
int energy_ = 100;
};
class Bug : public Animal, public Drawable {
public:
string GetType() const override {
return "bug"s;
}
void Draw(ostream& out) const override {
out << "(-0_0-)"sv << endl;
}
};
class Cat : public Animal, public Speakable, public Drawable {
public:
void Speak(ostream& out) const override {
out << "Meow-meow"sv << endl;
}
void Draw(ostream& out) const override {
out << "(^w^)"sv << endl;
}
string GetType() const override {
return "cat"s;
}
};
void DrawAnimals(const std::vector<const Animal*>& animals, ostream& out) {
/*if (const Animal* r = dynamic_cast<const Animal*>(&animals)) {
} else if (const Bug* c = dynamic_cast<const Bug*>(&animals)) {
}*/
}
void TalkToAnimals(const std::vector<const Animal*> animals, ostream& out) {
//?
}
void PlayWithAnimals(const std::vector<const Animal*> animals, ostream& out) {
TalkToAnimals(animals, out);
DrawAnimals(animals, out);
}
int main() {
Cat cat;
Bug bug;
vector<const Animal*> animals{&cat, &bug};
PlayWithAnimals(animals, cerr);
}
CodePudding user response:
I am going to explain for DrawAnimals
and you can extended to other functions by yourself.
What you did here:
void DrawAnimals(const std::vector<const Animal*>& animals, ostream& out) {
/*if (const Animal* r = dynamic_cast<const Animal*>(&animals)) {
} else if (const Bug* c = dynamic_cast<const Bug*>(&animals)) {
}*/
}
Is plain wrong for several reasons:
animals
is a vector- If you intended an individual element, then because
&animals[i]
(i = [0..animals.size()])
is a pointer to pointer (Animal**
) - Because
dynamic_cast<const Animal*>(animals[i])
(i = [0..animals.size()])
is the identity.
You need to work with each individual element of the vector:
void DrawAnimals(const std::vector<const Animal*>& animals, ostream& out) {
for (auto animal : animals) {
if (const Drawable* r = dynamic_cast<const Drawable*>(animal)) {
// this animal is Drawable
} else if (const Bug* c = dynamic_cast<const Bug*>(animal)) {
// this animal is a Bug
// only issue here: Bugs are also Drawable
// so this code will never be reached
}
}
}
Question: Why are some animals Drawable
and other don't?