Single container of different objects that all inherited the same class - c++

I'm trying to accomplish something but am unsure if it's even possible.
The quick idea is, I'm writing a game and want to have a single array (or vector) of different monsters. Every class that inherits the main class Monster simply overrides its functions (but doesn't add any new ones).
Then, when I go through the list of monsters, I can just call the same functions that all of them have.
Here's some code to show what I'm trying to accomplish:
class Monster
{
public:
int hp; //hit points
int atp; //attack power
int def; //defense
bool attacking;
bool defending;
virtual void attack();
virtual void defend();
};
void Monster::attack()
{}
void Monster::defend()
{}
class Goblin: public Monster
{
public:
virtual void attack() override;
virtual void defend() override;
};
void Goblin::attack()
{
//Goblin's attacking patterns
}
void Goblin::defend()
{
//Goblin's defending patterns
}
class Orc: public Monster
{
public:
virtual void attack() override;
virtual void defend() override;
};
void Orc::attack()
{
//Orc's attacking patterns
}
void Orc::defend()
{
//Orc's defending patterns
}
int main(void)
{
//This is where I'm not sure what to do:
//Initialize monsters. Make some Goblins, some Orcs
int num_monsters = 10;
Monster* monster_list;
monster_list = new Monster[num_monsters];
for (int i = 0; i < num_monsters; i++)
{
int which = rand() % 2;
switch (which)
{
case 0: //Goblin
monster_list[i] = new Goblin;
break;
case 1: //Orc
monster_list[i] = new Orc;
break;
}
}
bool quit = false;
while (quit == false)
{
for (int i = 0; i < num_monsters; i++)
{
if (monster_list[i].attacking == true)
monster_list[i].attack();
if (monster_list[i].defending == true)
monster_list[i].defend();
}
}
}
Hopefully that illustrates what I'm trying to do.
I know this doesn't work, but I'm not sure how to make it work.
Thanks for any advice on this!

You'll need to use a vector of pointers to a base class.
std::vector<Monster*> monsters;
monsters.push_back(new FireDragon());
monsters.push_back(new IceDragon());
Then you'll be able to iterate through the monsters vector and call a common method.
for(auto monster = monsters.begin(); monster != monsters.end(); monster++)
{
(*monster)->attack();
}
The classes:
class Monster {
public:
virtual ~Monster() {}
virtual void attack() = 0;
};
class FireDragon : public Monster {
public:
~FireDragon();
void attack()
{
std::cout << "Fire breath!" << std::endl;
}
};
class IceDragon : public Monster {
public:
~IceDragon();
void attack()
{
std::cout << "Ice breath!" << std::endl;
}
};
As a side note be sure to create virtual destructors in the derived classes or else the base class' destructor will be called.
ETA: Here is the implementation with smart pointers:
/*
Use std::unique_ptr<Monster> if your implementation doesn't need to pass the
monster objects around
*/
std::vector<std::shared_ptr<Monster>> monsters;
/*
Use std::make_unique<FireDragon>() if using unique_ptr
*/
monsters.push_back(std::make_shared<FireDragon>());
monsters.push_back(std::make_shared<IceDragon>());
for(auto monster : monsters)
{
monster->attack();
}

Related

Abstract class with inheritance classes and functions writing into separate vectors c++

Card game; I'm using abstract class for the "hands" which hold cards. The "hands" need to be slightly different but they share majority of the functions. So there is a Hand and a MasterHand which will inherit from the Hand and have an additional function. Everything goes through the deck which deals cards. My aim is to formulate the function within the Hand class in a way which allows writing into handV of the instance of the Abstract class that is called- regardless of it being Hand of MasterHand.. I've tried different methods but couldn't make any of them work.
class AbstractClass
{
virtual ~AbstractClass(){}
virtual void getCard(Card::card)=0 ;
};
class Hand:public AbstractClass
{
public:
vector<Card::card> handV;
virtual void getCard(Card::card k) override
{
writeIntoVector(k);
}
void writeIntoArray(Card::card g)
{
handV.push_back(g);
}
};
class HandMaster:public Hand
{
public:
vector<Card::card> handV;
// now here I would like to use the functions from Hand, but make them write into HandMaster.handV rather than Hand.handV
};
class Deck
{
void passCard(AbstractBase &x)
{
x.getCard(deck.back());
}
};
int main
{
AbstractBase* k=&h;
Hand* p = static_cast<Hand*>(k); // so I was trying to do it via casting in different convoluted ways but failed
MasterHand h2;
AbstractBase* m=&h2;
d.passCard(*k); // here I'd like the card to be passed to Hand.handV
d.passCard(*m); // here I'd like the card to be passed to MasterHand.handV
}
I added and simplified some of the code. But I will point you to some resources on polymorphism to get you started. I also remove the AbstractClass entirely since from an OOP perspective, you have objects that are Hands and another Master hand object.
https://www.tutorialspoint.com/cplusplus/cpp_polymorphism.htm
#include <vector>
#include <iostream>
//dummy class
struct Card{
int x;
};
class Hand{
public:
Hand(){}
std::vector<Card> handV;
virtual ~Hand(){}
virtual void getCard(Card k)
{
handV.push_back(k);
}
virtual void showHand()
{
for(std::vector<Card>::const_iterator it = handV.begin();
it != handV.end();
it++)
std::cout << it->x << " ";
}
};
class HandMaster: public Hand
{
public:
HandMaster(){}
//add additional methods
};
class HandOther: public Hand
{
public:
HandOther(){}
//add additional methods
};
class Deck
{
public:
std::vector<Card> deck;
Deck(){
Card c;
for(int i = 1; i <= 52; ++i){
c.x = i;
deck.push_back(c);
}
}
void passCard(Hand *x)
{
x->getCard(deck.back());
deck.pop_back();
}
};
int main()
{
Deck d;
Hand* p = new Hand();
HandMaster *m = new HandMaster();
HandOther * o = new HandOther();
for(int i =0; i < 5; ++i){
d.passCard(p);
d.passCard(m);
d.passCard(o);
}
std::cout << "\nHand:";
p->showHand();
std::cout << "\nHandMaster:";
m->showHand();
std::cout << "\nHandOther:";
o->showHand();
std::cout << "\n";
delete o;
delete p;
delete m;
}

C++ polymorphism. Methods

I have a small problem which I can't handle.
Currently I'm working over a project about a marathon between animals.
I'm obliged to use polymorphism even though it could be easier without.
Here's a sample of my code:
class Animal
{
public:
virtual void run()=0;
virtual bool return_if_finished()=0;
virtual float return_distance()=0;
}
class Turtle :public Animal
{
int id;
float distance; //etc.
public:
void run();
bool return_if_finished();
float return_distance();
void set_id(int i);
void a_friend();
}
class Snail :public Animal
{
float distance; //etc.
public:
void run();
bool return_if_finished();
float return_distance();
void broken_leg();
}
So that's a sample. All classes that inherit from the main class "Animal" have only three mutual methods. They also have some that only they do need.
If I want to write a code in a method where they "run" like that:
...
Animal* turtles = new Turtle[amount];
Animal* snails = new Snail[amount];
for(int i=0; i<amount; i++)
turtles[i].set_id(i);
I can't compile it because "class Animal has no member called "set_id"".
I could create all these methods for each class but that would be totally pointless. I bet there's a quick solution to that.
If I create a virtual void "set_id(int)" for the class "Animal" then I get the error message that not all classes that inherit from animal contain that method.
So any help would be very appreciated. Thank you
If I create a virtual void "set_id(int)" for the class "Animal" then I get the error message that not all classes that inherit from animal contain that method.
I suspect you defined Animal::set_id as a pure virtual, like this:
virtual void set_id(int) = 0;
What you really want is to define it in the Animal class as a virtual method, like this:
virtual void set_id(int _id) {id = _id};
Also, the id member variable needs to be moved to the Animal class instead of Turtle
EDIT:
Expanding the answer to include the full code:
class Animal
{
public:
Animal() : id(-1) {}
virtual ~Animal() {}
virtual void run() = 0;
virtual bool return_if_finished() = 0;
virtual float return_distance() = 0;
void set_id(int i) { id = i; }
private:
int id;
};
class Turtle :public Animal
{
public:
void run() {};
bool return_if_finished() { return true; };
float return_distance() { return 2.0; };
void a_friend() {};
};
class Snail :public Animal
{
public:
void run() {};
bool return_if_finished() { return false; };
float return_distance() { return 1.0; };
void broken_leg() {};
};
int main()
{
const int amount = 10;
Turtle turtles[amount];
Snail snails[amount];
for (int i = 0; i < amount; i++) {
turtles[i].set_id(i);
}
}
First of all, using:
Animal* turtles = new Turtle[amount];
Animal* snails = new Snail[amount];
is a bad idea.
The pointer arithmetic on turtles and snails will be based size of Animal. If you use tutles[i] for all i not equal to 0, you'll run into undefined behavior. There is probably an SO question somewhere about that.
Use a vector of pointers instead. It will be also easier to initialize them.
std::vector<Animal*> turtles(amount); = new Turtle[amount];
for(int i=0; i<amount; i++)
{
Turtle* tptr = new Turtle;
tptr->set_id(i);
turtles[i] = tptr;
}
Better yet, use a smart pointer.
std::vector<std::shared_ptr<Animal>> turtles(amount); = new Turtle[amount];
for(int i=0; i<amount; i++)
{
Turtle* tptr = new Turtle;
tptr->set_id(i);
turtles[i] = std::shared_ptr<Animal>(tptr);
// Or
// turtles[i].reset(tptr);
}

Calling a derived virtual function

I'm still fairly new to C++ and inheritance has gotten me in a pickle.
I know this works in C# since I'm always using Base.();
I'm hoping to be able to call a vector array of PlayerCharacter, derived from Entity.
Currently when I call it, it only calls Entity's update method.
int main()
{
vector<Entity*> list;
list.push_back(&PlayerCharacter());
for(int i = 0; i < list.size(); i++)
{
list[0]->Update();
}
}
class Entity
{
public:
Entity(void);
~Entity(void);
int hitpoints;
virtual void Update(void);
};
void Entity::Update(void)
{
int a = 0;
a++;
}
class PlayerCharacter : public Entity
{
public:
PlayerCharacter(void);
~PlayerCharacter(void);
bool Move();
void Update() override;
};
void PlayerCharacter::Update(void)
{
int a = 0;
a--;
}
list.push_back(&PlayerCharacter()); i think this is undefined behavior in your code.
In your case you should allocate the data on the heap like this: list.push_back( new PlayerCharacter() ); otherwise if you do this &PlayerCharacter() then the PlayerCharacter variable will be destroyed immediately and the pointer inside the list will point to garbage bytes.
Also to track which function is called you can use the debugger or print something in the console from each Update function.
This Works :
Few changes though : 1) You dont need to put Override 2) Definition of Constructor and destructor once declared 3) Created object of derived class and passed it to the list.
Output is : Inside PlayerCharacter
If you want to call base class update method method remove the volatile keyword. Or use base class pointer pointing to base class object.
class Entity
{
public:
Entity();
~Entity();
int hitpoints;
virtual void Update(void);
};
Entity::Entity()
{
}
Entity::~Entity()
{
}
void Entity::Update(void)
{
std::cout << " Inside Entity" <<std::endl;
int a = 0;
a++;
}
class PlayerCharacter : public Entity
{
public:
PlayerCharacter();
~PlayerCharacter();
bool Move();
void Update();
};
void PlayerCharacter::Update(void)
{
std::cout << " Inside PlayerCharacter" <<std::endl;
int a = 0;
a--;
}
PlayerCharacter::PlayerCharacter()
{
}
PlayerCharacter::~PlayerCharacter()
{
}
int main()
{
vector<Entity*> list;
PlayerCharacter ObjPlayerCharacter;
list.push_back(&ObjPlayerCharacter );
for(unsigned int i = 0; i < list.size(); i++)
{
list[0]->Update();
}
}

Is there any way to call unknown methods of a template argument class?

I once implemented a state machine like this:
class Player
{
public:
int Run();
int Jump();
int Stop();
private:
class State
{
public:
virtual int Run() = 0;
virtual int Jump() = 0;
virtual int Stop() = 0;
};
class StandingState : public State
{
virtual int Run() { /*...*/ }
virtual int Jump() { /*...*/ }
virtual int Stop() { /*...*/ }
};
class RunningState : public State
{
virtual int Run() { /*...*/ }
virtual int Jump() { /*...*/ }
virtual int Stop() { /*...*/ }
};
// More states go here!
std::list<State*> states;
State* currentState;
};
int Player::Run()
{
int result = m_currentState->Run();
// do something with result
}
int Player::Jump()
{
int result = m_currentState->Jump();
// do something with result
}
int Player::Stop()
{
int result = m_currentState->Stop();
// do something with result
}
Fairly textbook I should think: Player delegates the calls from outside to its current State object, and does something with the result (possibly transitioning to another state). Essentially, each state knows how a given action affects it, but it's up to the state machine to wire the various states together. I found this to be a good separation of concerns.
But I'm seeing a possibility for abstraction here. The entire system is defined by the interface of the State class:
Both the state machine and the substates implement State
The state machine keeps a pointer to all possible States and the current State
Whatever method of State is called on the state machine, it is undiscerningly forwarded to the current state.
So, we can totally make this a class template, right? Look:
template< class StateInterface >
class StateMachine : public StateInterface
{
// public methods already declared in StateInterface
protected:
std::list<StateInterface*> states;
void AddState(StateInterface* state);
StateInterface* currentState;
};
class PlayerStateInterface
{
public:
virtual int Run() = 0;
virtual int Jump() = 0;
virtual int Stop() = 0;
};
class Player : public StateMachine< PlayerStateInterface >
{
public:
virtual int Run() { currentState->Run(); /* do stuff */ }
virtual int Jump() { currentState->Jump(); /* do stuff */ }
virtual int Stop() { currentState->Stop(); /* do stuff */ }
};
Of the above points, this has 1 and 2 covered, but what about 3? I still have to manually delegate the calls to the current state in the concrete state machine implementation. Is there a way to move that functionality to the StateMachine template? Can I somehow express that whenever a method of StateInterface is called on StateMachine it should call the same method on currentState, when I don't know the names or signatures of StateInterface's methods?
If you're looking for a general answer to the case where Run, Jump, and Stop have different signatures, I don't know if there's a good solution. However, in your example they all have the same signature, which suggests to me that the following approach might work:
#include <iostream>
class AbstractState
{
public:
virtual void write1() = 0;
virtual void write2() = 0;
};
class State1: public AbstractState
{
public:
virtual void write1() { std::cout << "1-1" << std::endl; }
virtual void write2() { std::cout << "1-2" << std::endl; }
};
class State2: public AbstractState
{
public:
virtual void write1() { std::cout << "2-1" << std::endl; }
virtual void write2() { std::cout << "2-2" << std::endl; }
};
template <typename StateInterface>
class Player
{
public:
Player(StateInterface *s_):
s(s_)
{
}
void setState(StateInterface *s_)
{
s = s_;
}
void execute(void (StateInterface::*method)())
{
(s->*method)();
}
private:
StateInterface *s;
};
int main()
{
State1 s1;
State2 s2;
Player<AbstractState> p(&s1);
p.execute(&AbstractState::write1);
p.execute(&AbstractState::write2);
p.setState(&s2);
p.execute(&AbstractState::write1);
p.execute(&AbstractState::write2);
return 0;
}
I was able to compile and run this with GCC 4.5.2 and got the expected result, namely:
1-1
1-2
2-1
2-2
As I said, I'm not sure that there's a good way to extend this to the case where the different member functions of AbstractState take different parameters or return different values, and there may be other drawbacks that I haven't considered yet. It isn't quite as nice as what I think you were hoping to find, but hopefully this will at least serve as a good starting point.

Is this template visitor really dynamic?

I have been playing around with various methods of making the Visitor pattern in C++ more dynamic, such that sibling classes don't have to know about each other, and that allows later extension of the visitor hierarchy. I came up with this example based on "More Effective C++" by Scott Meyers:
class Dummy
{
public:
void collide(int& gameobject) { }
};
class DynVisitor
{
public:
template<class Visitor=Dummy, class Arg=int>
void visit(Arg& target)
{
Visitor* vis = dynamic_cast<Visitor*>(this);
if(vis != nullptr)
{
vis->collide(target);
}
else
{
cerr<<"No implementation!"<<endl;
}
}
virtual ~DynVisitor() { }
};
class GameObject
{
public:
virtual ~GameObject() { }
virtual void collide(GameObject& obj)
{
cout<<"Default collide implementation"<<endl;
}
virtual void accept(DynVisitor* vis) = 0;
};
class AsteroidVisitor
{
public:
virtual void collide(Asteroid& target) = 0;
virtual ~AsteroidVisitor() = 0;
};
class Collider : public DynVisitor, public AsteroidVisitor
{
public:
virtual void collide(Satellite& target) { cout<<"Satellite collision."<<endl; }
virtual void collide(Spaceship& target) { cout<<"Spaceship collision."<<endl; }
virtual void collide(Asteroid& target) { cout<<"Asteroid collision."<<endl; }
virtual ~Collider() { }
};
class Asteroid : public GameObject
{
public:
virtual void accept(DynVisitor* visitor)
{
visitor->visit<AsteroidVisitor, Asteroid>(*this);
}
};
int main(int argc, char** argv)
{
DynVisitor* coll = new Collider();
GameObject* ast = new Asteroid();
ast->accept(coll);
delete ast;
delete coll;
return 0;
};
This appears to work as I would expect, printing out "Asteroid collision" when the GameObject passed is an Asteroid, and I can add classes to the hierarchy just by defining a new ABC with a collide() method and extending DynVisitor.
My question is, when I add a new class to the hierarchy, does DynVisitor need to be recompiled?
EDIT: Added the asteroid class... sorry about that.
All objects can collide with each other, so they still need to be visitors of each other and hence there is no added "dynamism". DynVisitor is a template and thus needs to be in the translation unit and will be recompiled everytime. In fact, in this example, DynVisitor does't give any benefit because the accept() function can call the collide() function instead of the template visit() function.