c++ How to make changes to the same object across multiple classes? - c++

Noobie here. I'm trying to make changes to the Player object mainCharacter across multiple classes. I currently have a Player object declared as seen below. The Player is able to teleport to various worlds and fight monsters.
All of that code works. Once the enemy of one world is defeated, they stay defeated. My problem is that when he teleports to another world, the Player's stats are all reset to their default values; he has full life points again even after sustaining damage from the enemy in the previous world.
How do I make changes to the same Player object across multiple classes, or worlds? I figure there's a problem in my declarations but I'm not sure. I appreciate any input. Thanks!
Where the mainCharacter object is declared:
class SpaceList
{
protected:
class SpaceNode
{
friend class SpaceList;
Player mainCharacter;
Space* thisSpace;
SpaceNode* next;
SpaceNode(int m, SpaceNode* next1 = NULL)
{
if(m == 0)
{
thisSpace = new EntranceHall(&mainCharacter);
}
else if(m == 1)
{
thisSpace = new WaterSpace(&mainCharacter);
}
Part of Player.hpp:
class Player: public Interactable
{
protected:
Backpack myBackpack;
public:
Player();
virtual interactableType getInteractableType();
virtual int interact();
virtual int attack();
virtual void defend(int);
Part of Player.cpp:
Player::Player()
{
healthPoints = 10;
numberOfAttackDice = 1;
sidesOfAttackDice = 6;
numberOfDefendDice = 1;
sidesOfDefendDice = 6;
}
mainCharacter starts off at Entrance (Entrance.cpp):
EntranceHall::EntranceHall(Interactable* mainCharacter)
{
interactableGrid[6][3] = mainCharacter;
interactableGrid[0][3] = new Portal(0);//entrance portal
interactableGrid[3][3] = new InterestPoint(0);//stone mural
}
mainCharacter may later teleport to Water World, default values reset (Waterspace.cpp):
WaterSpace::WaterSpace(Interactable* mainCharacter)
{
interactableGrid[3][0] = mainCharacter;
interactableGrid[3][3] = new Boss(this->getSpaceType());

Remove the has-a relationship between SpaceNode and Player - create an instance of Player somewhere outside and use a pointer to refer to it, like you're used to. Or just make it static, so that there's only one instance that does not get reconstructed (or rather constructed separately for each SpaceNode).
Notes:
Don't implement linked lists yourself, this data structure does not even fit here. Try std::vector.
Better switch to smart pointers. You might be leaking memory without even knowing it.

Related

Change base class from derived class permanently?

So, my problem is that i want to modify my parent class Board from a derived class in such a way that it applies to all other objects of the derived class. Ex. If I input a 3 on getTest() in players[1] players[2] will be able to print that same value. Is this posible?
class Board {
public:
int test;
virtual void getTest() = 0;
};
class Player : public Board{
public:
int playerNum;
Player(int _playerNum){
playerNum = _playerNum;
}
void printTest(){
cout << "The value of test is: " << Board::test;
}
void getTest(){
cin >> Board::test;
}
};
int main(){
Player players[] = {1,2};
players[1].getTest();
players[0].printTest();
return 0;
}
It is indeed possible to share state between all instances that derive from Board.
As mentioned in the comments, if Board::test were given the static storage-class duration, this would be a variable shared across all instances of Player and any other classes that derive from Board now and forever. Technically, the variable is actually a member of the type rather than instances of the type. This will work, however in terms of design, it has some strange implications.
Namely, Player::getTest() is a non-static member-function, which sets static state that will be shared across all derived classes of Board. This can work as a quick and dirty change to code, but can lead to maintenance burdens and cognitive overhead. For example, if you have code in different subsystems like a Player and Widget that both implement Board, you get into a case where:
// subsystem A:
player.getState();
// subsystem B:
widget.printTest(); // not obvious that this comes from the player in "subsystem A"
The bigger the code gets, the harder it is to understand.
Additionally, static variables have issues working across translation units that can lead to initialization-order problems -- and it's often a mess that's not worth fighting with.
Depending on what it is you actually intend to share, often times it can be better for design to explicitly state as such using an object that explicitly indicates its shared ownership -- such as a std::shared_ptr.
This won't be implicitly passed to everything as you originally requested -- but that's actually a good thing since you can explicitly state what data you want shared and where. This also lets you decide if ever there's a case where you don't want everything shared between them, you can design it as such.
A simple example with your current code would instead be done like:
class Board {
public:
virtual void getTest() = 0;
};
class Player : public Board{
public:
int playerNum;
std::shared_ptr<int> test;
Player(int _playerNum, std::shared_ptr<int> _test){
playerNum = _playerNum;
test = _test;
}
void printTest(){
cout << "The value of test is: " << *test;
}
void getTest(){
cin >> *test;
}
};
int main(){
std::shared_ptr<int> test = std::make_shared<int>(0);
// explicitly share 'test' between the two players
Player players[] = {Player{1,test}, Player{2,test}};
players[1].getTest();
players[0].printTest();
return 0;
}
This would produce the same results as you originally requested, but it explicitly shared test rather than implicitly doing this behind static variables.
Explicitly stating the shared state here also allows you to produce more Player objects later that might share a different set of test state than the first created ones (depending on what this state is, this can be quite useful).
Overall, it's often better in terms of design for readability and overall cognitive overhead to be explicit about the data you want shared.

function inside objects oop

I don't understand what is the point of having a function inside an object if you can even modify data outside the object for example (I'm using struct for this example):
int lamborghini_horsepower1 = 350;
struct car {
string model;
string color;
int horsepower;
void check(int horsepower) {
if (horsepower > 349) {
cout << "this car has many horsepowers";
}
}
};
car ford;
ford.check(lamborghini_horsepower1);
in this case it would run anyways.
it would make sense if the function could only operate inside data of the object because as it say they are the data of the object and why can the function access to others variables? for example what if you pass another variable in this case lamborghini_horsepower is not part of the the object ford. and still can be cecked by the ford function even if they are different veichle.
are for class different?
In structs, functions don't have too much of an impact because data can be modified from the outside. However, they still can act as a convenience feature, especially when properly written. Your function takes horsepower as an argument, which is unnecessary because horsepower is already a field in the struct. If you change your function to:
void check() {
if (horsepower > 349) {
cout << "this car has many horsepowers" << endl;
}
}
you can call it with ford.check() and it'll automatically retrieve the horsepower from the ford variable. In classes, fields can be declared as private, which means that they can't be accessed from the outside and must be modified purely with functions defined inside the class.
are for class different?
Classes are not accessible from the outside by default, so if you did
class car{
string model;
string color;
int horsepower;
void check(int horsepower) {
if(horsepower>349)
{
cout << "this car has many horsepowers";
}
}
};
Then nothing in that struct would be accessible from outside the class. But there is a way to modify the what variables and functions can be accessed from the outside with access modifiers.
The purpose of making functions and variables inaccessible outside the object is to protect them from being unintentionally called or altered
The short answer is that your example wouldn't be very efficient for objects. I would just keep the function outside the struct in that example.
The purpose of classes and structs is to put variables and functions into one package. The example you have doesn't require an object. The basis behind object design is to mimic real world objects by giving them abilities(functions) and properties (variables).
The check() function here isn't an ability we normally find in cars. Instead, a car has certain properties like color, speed, and direction. A car also has abilities like accelerate, reverse, turn left and turn right. With this we can create a car object with these properties (variables) and abilities (functions)
struct Car
{
int speed;
std::string color;
std::string direction;
Car() // As soon as the object is created, this function will be called and set speed to 0.
{
speed = 0;
}
void speedUp()
{
speed += 5;
}
void slowDown()
{
speed -= 5;
}
void stop()
{
speed = 0;
}
void reverse()
{
stop() // This will stop the car first
speed -= 2; // Move the car backwords
}
void turnLeft()
{
direction = "left";
}
void turnRight()
{
direction = "right";
}
};
So now you can create different objects of the same class\struct with different speeds, direction, and color.

How to "skip" certain child class functions

I wasn't sure how to exactly title this, but I am trying to figure out something with polymorphism.
So basically, I want to have an array of the parent class (object) that holds a bunch of it's child classes (ones that are and aren't collidable). However, I want to be able to put this array into a loop and run the collision function for only the collidable child class, but since the other child class doesn't have a collide function, how can I do this?
(Looks something like this)
class Object
{
protected:
Image image; // Pseudo code to make point
public:
void Collision() = 0;
//Constructor/Destructor
Object(void);
~Object(void);
};
class Collidable : Object
{
private:
Position myPosition; // Pseudo code to make point
public:
void Collision(); // Has collision function for parent class
//Constructor/Destructor
Collidable(void);
~Collidable(void);
};
class Uncollidable : Object
{
private:
Position myPosition; // Pseudo code to make point
public:
// No collision function for parent class
//Constructor/Destructor
Uncollidable(void);
~Uncollidable(void);
};
int main()
{
Collidable collide1, collide2, collide3;
Uncollidable uncollide1, uncollide2, uncollide3;
Object *objects[] { collide1, collide2, uncollide1, uncollide2, uncollide3, collide3 };
for(int i = 0; i < 6; i++)
{
objects[i].Collide(); // Should not work.
}
return 0;
}
^(this was just an example to help show my question, do pardon some of the syntax errors if any)
I'm pretty sure, however, that something like this would be an error since void Collide() doesn't exist in the Uncollidable class. So how might I be able to still run the void Collide() function in the loop while avoiding error? Or is something like this impossible and I just have to make two separate arrays?
I hope I explained my question well.
(I tried to research this, but every time I tried I just got sent to the basics of polymorphism)
You can just do this:
for(int i = 0; i < 6; i++)
{
Collidable c = dynamic_cast<Collidable*>(objects[i]);
if(c != nullptr) // dynamic_cast will return null if objects[i] is not of type Collidable
c->Collide(); // Should work.
}
In your code there is one bug, you have made Collide() pure virtual in class Object, but you are not overriding it in Uncollidable. It will not work. Either override it in Uncollidable (which is inappropriate), or give a default body to Object::Collide() (which is inappropriate also).
There is a better design, put all the common interface in Object, separate out different behaviors in other interface. It will lead to good OO design ( compliant with IS-A relationship)
class Object
{
protected:
Image image; // Pseudo code to make point
public:
Object(void);
~Object(void);
//other common interface
};
class Collidable // this is an interface that represent 'collidable' behavior
{
public:
virtual void Collision() = 0;
}
class CollidableObject : public Object, public Collidable
{ ... }
class UncollidableObject : public Object
{ ... }
Note: Object must be inherited publicly, otherwise you will not be able to treat object os CollidableObject and UncollidableObject as object of Object.

Accessing child function, while using parent class

I am doing an assignment for the university course and me and my partner have a problem. Program we are making is a game.
We have several classes, which all inherit from the base class, called Creature. These are all enemies player needs to deal with and they all run their own AIs. There are 4 different types of child classes, all within namespace Creature(Including parent, Creature), with one class having special functions that only it needs. This class is called Bunny.
Now, my job is to call AI functions as needed. Problem is, I do not always know what class I am calling out, as such, when I ask the game board to tell me what Creature I get.
All enemies are saved as pointers like so, in game board squares:
struct Square
{
// Pointers to Morso class, where the enemy is saved
Creature::Creature* creature;
//Undeeded stuff removed
};
Now, this is all and fine until we need to access to special functions. Pupu will multiply if certain conditions are filled. As such, with in Pupu there are few functions I need to call to make sure it carries out it's act correctly.
However, here comes the problem.
I call our board class to give me the creature that is in the coordinates I give to it.
void GameEngine::GameEngine::runAI()
{
Creature::Creature* creature= NULL;
for(unsigned int y = 0; y < dimY; y++)
{
for(unsigned int x = 0; x < dimX; x++)
{
Coordinate target;
target.setX(x);
target.setY(y);
creature= board_->returnCreature(target);
//If there is a creature in the target, run its AI
if(creature!= NULL)
{
//If it is, check special procedures
if(creature->returnType() == "bunny")
{
bunnyReproduce(creature);
}
creature->ai();
}
}//for x
}//for y
}
Now, :
void GameEngine::GameEngine::bunnyReproduce(Ccreature::Creature* creature)
{
//Checks that it really is a bunny
if( creature->returnType() != "bunny"){ return; }
//Check is there another bunny near
creature->checkForMate();
}
The problem is, creature, at this point, can't call for checkForMate, which is public member of Bunny, but not Creature. Do we need to make virtual function into Creature?
I tried making checkForMate into Creature::Bunny, but since the original value I try to give to it is Creature class, I can't do so. Do we need to to create an empty virtual function in Creature class and then override it it Bunnyclass?
I am running Qt Creator 2.7.0, with QT 5.0.2.
You should add virtual function reproduce to Creature class and implement it in Bunny or any other creature you may later add to the game. So that any creature will reproduce itself in it's own way. You don't even need to check creature type in this case. Since if you have some non reproducible creatures, you may just implement reproduce as empty method that will do nothing.
Ideally, your engine shouldn't need to care at all what kind of creature it's working with.
If you want the bunny to reproduce on each ai() step, why not do it in the bunny's ai()?
After all, shouldn't it be the bunny's responsibility to decide when to reproduce, rather than some almighty external Engine?
void Creature::Bunny::ai()
{
if (niceMateNearby())
reproduce();
else
eatCarrotsAndJumpAround();
}

Is it possible to initialise two classes, that require pointers to each other, at the same time?

I am making a snake game. I have two classes, snake and food. When I call snake->move() it needs to check that there are no collisions and for this purpose it needs to know what food's position is and therefore requires a pointer to food. food has a function that moves it to a new random position, move->setNewPosition(), which needs to know the position of snake so that it doesn't collide with the snake when it moves. For this purpose, it requires a pointer to snake.
Therefore, for both classes, I would need to supply a pointer to the other class which must be initialised. But to initialise the other class I need to initialise the other class and so on. Is there any way to initialise two classes, that require pointers to each other, at the same time?
If not, what would be a better way of structuring my program that would allow me to check the coordinates of the other class?
If i don't misunderstand you, create init function that call before game loop starts:
void initSnake()
{
auto snake = new Snake();
auto food = new Food();
snake->setFood(food);
food->setSnake(snake);
}
They just need the facility to find the location of other snakes and food items when their movement functions are invoked. There's no need to know of their existence at initialisation time!
You can therefore have a collection of snakes and a collection of food items, and pass a reference to those collections to any newly created snakes and food items. Just create those collections first.
You could do this via another class, perhaps, which could also act as a factory.
class GameManager;
class Snake
{
friend class GameManager;
public:
int getX() { return _x; }
int getY() { return _y; }
void setPosition(int x, y) { /* ... */ }
private:
Snake(GameManager* manager, int x, int y) : _manager(manager), _x(x), _y(y) {}
GameManager* _manager;
int _x, _y;
};
class GameManager
{
public:
const std::vector<Snake*>& Snakes() { return _snakes; }
Snake* SpawnSnake(int x, int y)
{
Snake* newSnake = new Snake(this, x, y);
snakes.push_back(newSnake);
return snake;
}
private:
std::vector<Snake*> _snakes;
};
(Just an example. Code not tested to see if it actually compiles. E&OE)
The GameManager ensures that all created snakes are found in the snakes vector because the Snake constructor is private. Each snake can call _manager.Snakes() to get a vector containing all the other snakes in the game which it can then query individually for their positions. This is easily generalised to support food items as well.
This has the small advantage over the "construct-initialise" pattern suggested in other answers in that it ensures that when you get a new Snake object it is actually ready for use... this example isn't quite RAII, but it would require a minimum of effort to make it reasonably exception-safe.
You can define one base class for them, which has these methods:
virtual void setPosition(const int x, const int y)
virtual void getPosition(int &x, int &y) const
Snake should use them too, just override them if you need to. Now both classes can call each other's setPosition and getPosition directly if you give the other object as a parameter with type Base.
An other way would be; In your main()-function, or wherever you define your snake:
int main()
{
Snake* s = new Snake;
Food* f = new Food;
Snake->setLocation(0,0); // Wherever you want the snake to start from
}
And whenever you create a new food, give it snake's location: f->setRandomLocation(snake->getLocation()) where the parameter would be coordinates where NOT to place it.
One alternative would be to have a Manager class which both of them send their requests to, which would make more sense (but doesn't solve your particular problem).
Nevertheless, if you have class A and class B, and each one needs the other, you can do the following:
A *a = new A;
B *b = new B;
// check a and b to make sure they are not NULL
a->set_b(b);
b->set_a(a);
Mmn, not sure how your game works but I assume there would be a lot of food objects?
Maybe an idea would be to create a Collision class that accepts a Snake player and stores all the Food players in the game.
So the Collision constructor might look like this
Collison(Snake &snake, Vector<Food*> &foods)
{
}
The Collision class would also have an collision update to loop that you call somewhere in your code.. This loop would check if the snake object collides with a food object.. and you can do whatever you want.. remove the food from the foods vector change the food position, whatever.
collison.UpdateCollisions() ;
I would suggest breaking the cyclic dependency, instead of hammering it in: make both moving functions take the environment (i.e. a list of things it can collide with) as a parameter.