Create a program which creates 3 monster objects and stores them in a vector. re
ID: 3529414 • Letter: C
Question
Create a program which creates 3 monster objects and stores them in a vector. read object data. display object data. classes: Monster Class Properties: weapon object playername type troll zombie creeper level strength member Functions: default constructor constructor with parameters set and get function for all data members Weapon Class Properties: type club disease bomb durability strength member functions: default constructor constructor with parameters set and get methods for all data membersExplanation / Answer
Very carefully i'm going to say that you'll probably also need the "double dispatching pattern". What on Earth is that monster (no pun intended)?Well, probably you're going to want to do different things when an Orc is attacking a Troll or a Goblin. The problem is, how is that attack function going to know whether it is attacking Troll or Goblin?
If you know about function overloading, you might think that's going to solve your problem because you say "hey, i just overload attack for trolls and goblins". Unfortunately, it's not going to work.
// overloading looks usefull, but it's not going to work.
void Orc::attack(Troll* victim) {}
void Orc::attack(Goblin* victim) {}
The problem is that when the actual attack happens, you'll only have Entity pointers (remember? you wanted to store all those monsters in one big container). Take the following as an example. We'll have two monsters: one Orc and one Troll.
// our test case
Entity* monster1 = new Orc;
Entity* monster2 = new Troll;
// ... blablabla ...
// the actual attack:
monster1->attack(monster2);
OK, test case is settled, now we have to get it work. How do we know what attack function to use? Orc's? Troll's? Goblin's? Simple, attack will be a virtual function (read the FAQ :) ), and since monster1 is an Orc, we'll get in Orc's attack function. Huray, now the other one.
How does Orc's attack function know wether it's attacking a Troll or Goblin? Simple, we've overloaded it for both ... oh wait ... We're not passing a Troll or Goblin pointer to attack but an Entity pointer! The overloading mechanism is never going to know what function to choose! Even worse, it will not compile, because there isn't a single attack function that accepts an Entity pointer!
It turns out, we must have an attack function that accepts an Entity pointer. Easily done, but problem now is that we'll end up in that function regardless if the Orc is attacking a Troll or Goblin. How does the attack function know which one it is?
void Orc::attack(Entity* victim)
{
// am i attacking a Troll or Goblin? or maybe another Orc?
}
There are various ways to solve this. One way is to use typeid or dynamic_casts to make a typeswitch and do what to do per type. Like following:
void Orc::attack(Entity* victim)
{
if (Troll* troll = dynamic_cast<Troll*>(victim))
{
// victim is troll (oh dear)
}
else if (Goblin* goblin = dynamic_cast<Goblin*>(victim))
{
// victim is goblin (too easy!)
}
else
{
// i dunno what it is ... run!
}
}
While it works, this is plain ugly but more importan, dynamic_casts are slow, and the complexity is even linear in the number of kind of monsters. Don't want that.
Another, more interesting, sollution comes from the observation that Orc's attack function doesn't know of what type the victim is, but it does know that the aggressor is an Orc! So, you reverse the logic and you let the victim be attacked by an Orc! And then you can use overloading to determine by what kind of monster the victim is attacked. Moreover, since this "be_attacked" function is again a virtual function, the real idenity of the victim will be finally revealed!
All together:
class Orc;
class Troll;
class Goblin;
class Entity
{
public:
virtual void attack(Entity* victim) = 0;
virtual void be_attacked(Orc* aggressor) = 0;
virtual void be_attacked(Troll* aggressor) = 0;
virtual void be_attacked(Goblin* aggressor) = 0;
};
class Orc: public Entity
{
public:
virtual void attack(Entity* victim) { victim->be_attacked(this); }
virtual void be_attacked(Orc* aggressor) { // oh no, my brother is attacking me }
virtual void be_attacked(Troll* aggressor) { // oh dear }
virtual void be_attacked(Goblin* aggressor) { // too easy! }
};
class Troll: public Entity
{
public:
virtual void attack(Entity* victim) { victim->be_attacked(this); }
virtual void be_attacked(Orc* aggressor) { // oh no, not again! }
virtual void be_attacked(Troll* aggressor) { // Troll fight! }
virtual void be_attacked(Goblin* aggressor) { // pff! }
};
class Goblin: public Entity
{
// ... you get the idea :)
};
// SHOWCASE!
Entity* monster1 = new Orc;
Entity* monster2 = new Troll;
monster1->attack(monster2) // calls void Orc::attack(Entity*) which in turns calls Troll::be_attacked(Orc*)
}
Now the ugly typeswitches are replaced by two virtual function calls (hence double dispatcher :) ) which are both fast and O(1).
However, as you can see, the number of be_attacked functions grows N
Related Questions
Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.