• Advertisement
Sign in to follow this  

Cannot Access Class Functions and Variables

This topic is 3733 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm using classes and multiple files. I've defined each class in a header file, a class function file for each class, and I have a main.cpp file. I define the class objects in the main.cpp file. Now the problem is, because I'm not defining the class object until main, one of my classes can't access the class function and (public) variable of another. How do I accomplish this? Thanks in advance, Steve. Classes csBoard csInput Objects obBoard obInput Problem lines in csInput iMovepiece = obBoard.iBoard[iSqr]; obBoard.update(iMovepiece, iMovefrom, iMoveto); Clearly class object obBoard hasn't been defined yet (just the class definition) so gives a compiler error. It doesn't work with the class name csBoard either. Main File csBoard obBoard; csInput obInput;

Share this post


Link to post
Share on other sites
Advertisement
obBoard undeclared identifier. That's in the csInput class - I can see why it's complaining - a class object hasn't yet been created. But I don't know how to resolve the problem.

Share this post


Link to post
Share on other sites
Quote:
Original post by Steve Elliott
obBoard undeclared identifier.


You are going to have to post actual code. Try main.cpp, and the headers for the included classes. Use [source][/source] to get a ice syntax highlighted box.

Share this post


Link to post
Share on other sites

#ifndef BOARD_H
#define BOARD_H

class csBoard {
public:
int iBoard[64];
int *pBoard;
csBoard();
~csBoard();
void update(int iMovepiece, int iMovefrom, int iMoveto);
void draw();
};

#endif

#ifndef INPUT_H
#define INPUT_H

class csInput {
int iMove, iMovepiece, iMovefrom, iMoveto;
int iSqr, iConvertcol, iConvertrow;
char cCol, cRow;
bool bError, bPlaygame;

public:
csInput();
~csInput();
bool getmove();
void draw();
};

#endif

//----------------------------------------------------------------------------------

bool csInput::getmove()
{
// problem lines

iMovepiece = obBoard.iBoard[iSqr];

if (bPlaygame)
obBoard.update(iMovepiece, iMovefrom, iMoveto);

return(bPlaygame);
}

//----------------------------------------------------------------------------------

bool bPlaygame = true;

//----------------------------------------------------------------------------------

#include <iostream>
using namespace std;

#include "board.h"
#include "input.h"

//----------------------------------------------------------------------------------

int main()
{
csBoard obBoard;
csInput obInput;

do {
obBoard.draw();
obInput.draw();
bPlaygame = obInput.getmove();
}
while(bPlaygame);

return 0;
}




[Edited by - Steve Elliott on November 3, 2007 8:13:04 AM]

Share this post


Link to post
Share on other sites
You have no obBoard declared in the csInput class, that why you get an undeclared identifier error. And in the main() you didn't declare the bPlaygame var.

Share this post


Link to post
Share on other sites
Hi, the method GetMove uses obBoard which is declared in the main function. You should give a csBoard object as parameter to GetMove. That way in the main function, you may have

bPlaygame = obInput.GetMove(obObject);

edit: and don't forget to declare bPlaygame, as xissburg pointed

Share this post


Link to post
Share on other sites
Guys bPlaygame is declared, otherwise I would have listed another error message (I didn't copy and paste all the code). And I know obBoard isn't declared (I said that in my first post). Just don't understand the syntax required to solve the problem. :-)

KOzymandias that won't work because it's a compile error - not a runtime error.

Share this post


Link to post
Share on other sites
issburg, yes I edited the post to prevent further confusion. :-)

Ok using this code now compiles - but it doesn't work correctly. At least the thing is compiling now.


#ifndef INPUT_H
#define INPUT_H

class csInput {
int iMove, iMovepiece, iMovefrom, iMoveto;
int iSqr, iConvertcol, iConvertrow;
char cCol, cRow;
bool bError, bPlaygame;

public:
csInput();
~csInput();
bool getmove(csBoard obBoard);
void draw();
};

#endif


bPlaygame = obInput.getmove(obBoard);



[Edited by - Steve Elliott on November 3, 2007 9:56:42 AM]

Share this post


Link to post
Share on other sites
Refering to your first source posted:

A quick fix would be to send the obBoard as an argument to the getmove function


bool csInput::getmove(csBoard &obBoard)
{
// problem lines

iMovepiece = obBoard.iBoard[iSqr];

if (bPlaygame)
obBoard.update(iMovepiece, iMovefrom, iMoveto);

return(bPlaygame);
}







in input.h:

...
public:
csInput();
~csInput();
bool getmove(csBoard &obBoard);
void draw();
...







and in main:

...
do {
obBoard.draw();
obInput.draw();
bPlaygame = obInput.getmove(obBoard);
}
while(bPlaygame);
...







Or you could "fix" it the crude way:
in input.h add this at the top:

#ifndef INPUT_H
#define INPUT_H

#include "board.h"
extern csBoard obBoard;
...






and in main, declare the obBoard object at file scope:

#include "board.h"
#include "input.h"

bool bPlaygame = true;
csBoard obBoard;
int main()
{
...







There is also a third way you could go abaout it:
give the csInput class constructor a csBoard argument, and store it as a pointer or reference in the csInput class


...
#include "board.h"

class csInput {
int iMove, iMovepiece, iMovefrom, iMoveto;
int iSqr, iConvertcol, iConvertrow;
char cCol, cRow;
bool bError, bPlaygame;
csBoard &obBoard;

public:
csInput(csBoard &myBoard);
~csInput();
bool getmove();
void draw();
};

// the csInput constructor definition:
csInput::csInput(csBoard &myBoard)
: obBoard(myBoard)
{
...
}

// and a small change in main:
int main()
{
csBoard obBoard;
csInput obInput(obBoard);
...




The first or last solutions are the cleaner ones IMO.

Share this post


Link to post
Share on other sites
Quote:
Original post by Steve Elliott
Thanks guys. :-D

Can't help but think there's a better way of designing my classes - but that's ok for now.


Of course there is. :)

Updating the board is not logically a part of the process of getting input, so don't put that code there. The logical way to do things is to return the input from a function that "gets the input", and pass it along (as an argument) to the board. You can handle "is the game still going on?" by asking, not telling - there's no particularly good reason to communicate that state through a global. Now, between "input" and "board", which "knows" whether it's possible to keep playing? I would argue that the board would know, in general. So it makes sense to return that information from the update function.

Actually, it looks like the reason you want the Input class to "talk to" the board is to read its raw data, in order to figure out what piece is being moved - and then to tell the board that same information when you call update(). That's missing the point. Don't ask objects what they aren't specifically designed to tell you, and don't tell them things they know.

In fact, you probably don't need an input class at all. The board should be responsible for figuring out whether a particular move is legal, because it's the board which has the necessary information. Just get the input, and send it along. Design the input spec such that you don't need to know anything about the game logic - the board will check, and report whether the move was actually made, or was illegal.

It seems like you have some other fundamental misunderstandings, though - in particular, your classes look like they contain redundant data. The usual rules about scope apply: use a local when you can, and a class member when you have to (i.e. when it's actually logically "part of the object").

Consider dropping the Hungarian notation, too. It's actually seducing you into choosing worse "non-Hungarian-notation parts" of the variable names here. The positions on a Board aren't Boards; if you were to just write Board instead of csBoard and iBoard (not to mention pBoard and obBoard), this would stand out as kinda wrong - which it is.


// Splitting into separate files left as an exercise, of course. ;)
// I am using old-style comments to represent the bits you need to fill in,
// and regular ones to explain what is going on here.

enum { ILLEGAL_MOVE, GAME_STILL_GOING, YOU_WIN, YOU_LOSE, DRAW } GameStatus;

class Board {
// Don't make the data public! That's why we have this kind of
// organization in the first place; so we can *control* how 'cells'
// are modified.
int cells[64];

public:
// I assume the pointer pointed at the cells; that's totally redundant
// anyway - C++ lets you use the name of an array as if it were a
// pointer to the beginning element.
Board();
// From what is shown, it is extremely unlikely that you need a
// destructor at all.

GameStatus update(int from, int to);
void draw();
};

GameStatus Board::update(int from, int to) {
// Of course, "the complexity has to go somewhere":
// we need to put the code here that determines whether the move
// is legal, and what piece is being moved. But since 'cells' is
// OUR data, we are perfectly positioned to do so.
if (/* move is not legal - maybe split into another function */) {
return ILLEGAL_MOVE;
}
/* make the move */
/* return one of the other values accordingly */
}

void Board::draw() {
/* As before. */
}

#include <iostream>
using namespace std;

int main() {
Board board;
bool playing = true;
do {
board.draw();
int from = /* ask for input here */;
int to = /* ask for input here */;
switch (board.update(from, to)) {
case ILLEGAL_MOVE: /* complain */; break;
case GAME_STILL_GOING: break; /* nothing to do */
case YOU_WIN: /* report victory */; playing = false; break;
case YOU_LOSE: /* report defeat */; playing = false; break;
case DRAW: /* report stalemate */; playing = false; break;
}
} while (playing);
}



Yes, It's Really That Easy(TM).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement