1

I'm trying to use two classes' variables as to have access from class A's variables to class B's and vice versa. However, I can't figure a possible solution. It always ends up in either a loop, or the following error:

error: invalid use of non-static data member  

Here's the code sample:

Player.h:

  #ifndef _PLAYER_H_
  #define _PLAYER_H_

#include "Segment/Dynamic_Segment.h"

class Attributes_P;

class Attributes_P : public Attributes_DS{
  protected:
  int inv_mcols, inv_mrows;

  public:
  Attributes_P();
  void controls( int MKEY_UP, int MKEY_RIGHT, int MKEY_DOWN, int MKEY_LEFT );
  void inventory( int inv_mcols, int inv_mrows );
};

class Player : public Dynamic_Segment{
  protected:
  int   **inv;

  public:

  int   MKEY_UP, MKEY_RIGHT, MKEY_DOWN, MKEY_LEFT;

  public:

  Player();
  Attributes_P set;
  friend class Core;
  friend class Attributes_P;

};
#endif

Player.cpp:

#include "Segment/Player.h"

Attributes_P::Attributes_P(){};

Player::Player() : Dynamic_Segment(){
  set.inv_mcols = 0;
  set.inv_mrows = 0;
}

void Attributes_P::inventory( int inv_mcols, int inv_mrows ) {
  this->inv_mcols = inv_mcols;
  this->inv_mrows = inv_mrows;
  Player::inv = new int*[this->inv_mcols]; //<--- Error here
  for( int i = 0; i < this->inv_mrows; i++ ) {
    Player::inv[i] = new int[this->inv_mcols]; //<--- Error here
  }
}

void Attributes_P::controls( int MKEY_UP, int MKEY_RIGHT, int MKEY_DOWN, int MKEY_LEFT ) {
  Player::MKEY_UP = MKEY_UP; //<--- Error here
  Player::MKEY_RIGHT = MKEY_RIGHT; //<--- Error here
  Player::MKEY_DOWN = MKEY_DOWN; //<--- Error here
  Player::MKEY_LEFT = MKEY_LEFT; //<--- Error here
}

Have been banging my head against a wall for some time now... Any ideas would be appreciated!

user203432
  • 67
  • 6
  • You seem a bit confused. Why would `Attributes_P` know anything about the `Player` that was containing it? What languages have you used previously that might be affecting your concept of how objects work? – Peter Wood Jan 11 '13 at 15:53
  • It is not the concept that is, it is the result I wish to achieve. I do realize that it is indeed entirely wrong and illogical. And that is why I am looking for an alternative. – user203432 Jan 11 '13 at 16:10

3 Answers3

4

The members

Player::MKEY_UP
Player::MKEY_RIGHT
Player::MKEY_DOWN
Player::MKEY_LEFT

aren't static, so you can only access them through an object of type Player, not through the class instance.

Consider you create 2 player objects, p1 and p2. When you call Attributes_P::controls, which of the two object's members should you change? p1 or p2?

You can either declare those members as static if you want them to be shared between Player objects, or pass a specific Player object as parameter and access its members directly. This is part of the logic and the choice depends on how you want the program to work.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • AKA You need to pass the object as an argument to `Attributes_P::controls()` – crush Jan 11 '13 at 15:37
  • I do have player objects and read their respective MKEY_UP, MKEY_RIGHT, MKEY_DOWN, MKEY_LEFT. So I wish to refer to it as e.g. p1.MKEY_DOWN and set controls by p1.set.controls('w', 'a', 's', 'd'); and setting these values to MKEY_UP, MKEY_RIGHT, MKEY_DOWN, MKEY_LEFT – user203432 Jan 11 '13 at 16:04
  • @user203432 so then pass `p1` as argument. – Luchian Grigore Jan 11 '13 at 16:10
  • @LuchianGrigore Sorry, I can't seem to understand. After passing p1.set.controls('w', 'a', 's', 'd'); , I need to assign those values to MKEY_UP, MKEY_RIGHT, MKEY_DOWN, MKEY_LEFT which are back at class Player which owns a member of Attributes_P. – user203432 Jan 11 '13 at 16:13
  • @user203432 but you're trying to set the attributes of `Player` in the other class. Why not set them directly in `Player` - it already has a member `Attributes_p`. – Luchian Grigore Jan 11 '13 at 16:16
  • Due to syntax, although it is not essential, I need this syntax p1. **set** .controls('w', 'a', 's', 'd') – user203432 Jan 11 '13 at 16:17
  • @user203432 you can't unless `set` is aware of its owner (right now it isn't). If `Attributes_p` had a `Player` pointer as a member, it would work. – Luchian Grigore Jan 11 '13 at 16:19
  • But I can't create a member of class Player as I get the following error: `error: field ‘rel’ has incomplete type` when rel is a member of class Player – user203432 Jan 11 '13 at 16:21
  • I think this can't be accomplished because class Player hasn't been defined yet. Or will a pointer avoid this? – user203432 Jan 11 '13 at 16:22
  • @user203432 for a pointer member a forward declaration (`class Player`) is sufficient - you don't need a full definition. – Luchian Grigore Jan 11 '13 at 16:23
  • @LuchianGrigore This is what it spews out now: `error: request for member ‘inv’ in ‘((Attributes_P*)this)->Attributes_P::rel’, which is of non-class type ‘Player*’` – user203432 Jan 11 '13 at 16:32
  • 1
    @user203432 don't cast it. Just use `set` directly. I'm lost. I'm starting to think you should try a book :P – Luchian Grigore Jan 11 '13 at 16:33
  • Agh, I'm sorry to be such a pain, my mind is really vague atm, but please bare with me :(. I don't think I'm casting it, though, `void Attributes_P::inventory( int inv_mcols, int inv_mrows ) { this->inv_mcols = inv_mcols; this->inv_mrows = inv_mrows; &rel.inv = new int*[this->inv_mcols]; for( int i = 0; i < this->inv_mrows; i++ ) { &rel.inv[i] = new int[this->inv_mcols]; } }` - was this not what you had in mind? And having Player *rel; – user203432 Jan 11 '13 at 16:36
  • @LuchianGrigore This is what I did and got the above mentioned error. – user203432 Jan 11 '13 at 16:41
  • @user203432 just post a new question with the new code (narrowed down). It's difficult to tell in the comments. – Luchian Grigore Jan 11 '13 at 16:43
  • @LuchianGrigore Done, it's named C++ Class Entanglement [EDIT] – user203432 Jan 11 '13 at 16:48
2

You can not access the attributes MKEY_UP, MKEY_RIGHT, MKEY_DOWN, MKEY_LEFT & inv as they are private.

Make them private and write getter/setter!

Hennaldo
  • 155
  • 6
0

I think your data is probably too closely intertwined, and maybe should just be one class. One purpose of classes is to encapsulate the data, so you don't go fiddling with others' privates. Also there are other issues with what you are doing using new and arrays, etc. However...

In Attributes_P::inventory you are trying to modify inv, which is declared as a member of Player. But Attributes_P doesn't know which player you are referring to. You need to either

  1. pass a Player instance into the inventory function, or
  2. initialise Attributes_P with a reference to the player.

Option 1:

void Attributes_P::inventory(int inv_mcols, int inv_mrows, Player& player) {
    player.inv = ...
}

Option 2:

class Player; // needed so compiler understands next few lines refering to Player

class Attributes_P {
    Player& m_player;
public:
    Attributes_P(Player& player) : m_player(player) {
    }
};

class Player {
    Attributes_P m_attributes;
public:
    Player() : m_attributes(*this) { // pass self to Attributes_P constructor
    }
}

void Attributes_P::inventory(int inv_mcols, int inv_mrows) {
    m_player.inv = ...
}
Peter Wood
  • 23,859
  • 5
  • 60
  • 99