Class function needs to access the properties of the "aggregrate" class it belongs to

Okay so this might be long since I have the program separated into multiple files, but I want to know if I'm doing this the "right" way before going any further.. if you don't understand something, please ask! I tried to make this minimal to get the point across, although it's still pretty long :/

I made this basic example of a Game program.
The Game class has:
- a player property
- a float x property
- an update function.

The Player class has an update function as well.
The Game class's update function calls the player's update function. This is to organize my code better for when the game gets bigger, encapsulation and all that...

The problem I was having is that the Player::update function needs to access a property of the Game class that the player belongs to. Otherwise, the player has no idea how to update itself based on the "x" property of the Game class.

The way I figured out how to do this is to have the Game class pass its dereferenced this pointer to the Player's update function.

Code (not the actual game I'm working with, but it shows the same issue:

main.cpp
1
2
3
4
5
6
7
8
#include "Game.h"

int main()
{
    Game game;
    game.update();
    return 0;
}


Game.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef GAME_H
#define GAME_H

#include "Player.h"
//class Player;

class Game {
  public:
    Game();
    float getX() const;
    void update();

  private:
      float deltaTime;
      float x;
      Player player;
};
#endif // GAME_H 


game.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "Game.h"
#include "Player.h"

Game::Game()
: deltaTime(0.1f)
, x(42.f)
, player()
{}

float Game::getX() const
{return x;}

void Game::update()
{
    for (int i = 0; i < 10; i++)
        //calls its dereferenced self:
        player.update(deltaTime, *this);
}



Player.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef PLAYER_H
#define PLAYER_H

#include "Game.h"
class Game;
class Player {
  public:
    Player();
    void update(float deltaTime, Game game);
  private:
    static const float Speed;
    float pos;
};
#endif // PLAYER_H 


player.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include "Game.h"
#include "Player.h"

const float Player::Speed = 10.f;

Player::Player()
: pos(100.0f)
{}

void Player::update(float deltaTime, Game game)
{
   pos += Speed * deltaTime;
   pos += game.getX(); //The point of this is to use a property from the game.
   std::cout << pos << std::endl;
}



I'm probably not using the right term, I think it's aggregate. Basically, I am just wondering if this (by having a dereferenced Game as a passed function parameter) is the best way to make it so the Player::update() function can have access to the Game's properties.

Is there a better way to do this?

-------------------


tl;dr:
1
2
3
4
5
6
7
Game class:
    -Player object member
    -x variable
    -update() {call Player's update, update other things...}

Player class:
    -update() {needs access to Game's x variable, don't know the best way to do this} 

Last edited on
If you want to do it this way, I suggest you pass a reference to the Game object instead:

1
2
3
4
5
...
void update(float deltaTime, const Game &game); // game.cpp line 9 and player.cpp line 11
...
pos += game.getX(); // player.cpp line 14
...
Pass either a pointer or a reference, otherwise you're creating a new Game and a new Player each time update() is called, which besides being inefficient, doesn't make any sense.
If player only needs Game::x, perhaps it'd be better to pass that, rather than the entire Game. By the way, you should rename that. "x" doesn't mean anything.
1
2
3
4
5
6
7
//void Player::update(float deltaTime, float x)

void Game::update()
{
    for (int i = 0; i < 10; i++)
        player.update(deltaTime, this->x);
}
Thanks for reading,

If player only needs Game::x, perhaps it'd be better to pass that
In the actual game, the player's update() function relies on a lot of things.
It is checking for a lot of object collision with the Game's walls, the Game's enemies, etc...
The x was just the shortest variable name I could think of, I understand that the logic (incrementing the player's position based on the game's "X") doesn't make physical sense.

Pass either a pointer or a reference
Okay, so I should pass this into the update function instead of the dereferenced *this then?

1
2
3
4
5
6
7
8
9
10
//Player.h
    void update(float deltaTime, Game * game);

//player.cpp
void Player::update(float deltaTime, Game * game)
{
   pos += Speed * deltaTime;
   pos += game->getX(); //This point of this is to use a property from the game.
   std::cout << pos << std::endl;
}

So this is more efficient? Thanks again!

EDIT: Still need a bit more help
I should already know this from learning about pointers, but
is the above code the same as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

//game.cpp
void Game::update()
{
    for (int i = 0; i < 10; i++)
        player.update(deltaTime, *this);
}

//Player.h
void update(float deltaTime, const Game &game);


//player.cpp
void Player::update(float deltaTime, const Game &game)
{
   pos += Speed * deltaTime;
   pos += game.getX(); //This point of this is to use a property from the game.
   std::cout << pos << std::endl;
}


Both are same efficiency due to how compiler turns references into pointers, but using references is more "C++"-style than using straight pointers?
Last edited on
With the reference you can just forget about addresses and de-referencing, this could be seen as a good or a bad thing, depending on how you feel on a day to day basis.

Depending on perspective, references are "safer". Unlike with pointers, you can't have an uninitialsed reference and you can't make a reference point at something else (I think).

It is possible when using raw pointers to accidentally use it before it's properly initialised (although I can't see to do that when you're using "this"), or maliciously make it point to something else, unless you resort to the whole clumsy and confusing const pointer to const syntax, and you still have to worry about indirection...

Topic archived. No new replies allowed.