I have made a Class Board_t with a pointer board.
I dynamically allocate memory for board.
Board_t is a friend to another class Peg_t.
A third Class Hero_t is derived from Peg_t, needs to access board in a function.
Now as I see it, there shouldn't be any problem. But the compiler (I am using VS Express) is giving the error that board hasn't been declared.
class Board_t
{
protected:
char *board;
int Height, Breadth;
public:
Board_t ();
void SetBoard();
void PrintBoard();
friendclass Peg_t;
friendclass Hero_t; //I just added this to make sure that I was not making any mistake.(1)
~Board_t()
{
delete board;
}
};
//..........
class Peg_t
{
protected:
char Peg;
Control control; //An Enumerated Data type.
bool Moving;
int hei, wid;
public:
friendclass Board_t; //Same as (1)
};
//..........
class Hero_t: public Peg_t
{
public:
Hero_t (char, Control, bool);
void Move();
}Hero( 'H', User, true);
void Hero_t::Move()
{
//Other declarations not related to the problem
if (hei != 1 && board[Offset(hei-1,wid)] == blank) //Error
{
board[Offset(hei,wid)] = blank; //Error
hei--;
board[Offset(hei,wid)] = Peg; //Error
loopcheck = false;
}
}
I would really Appreciate it if someone would point out the error to me (the one I asked, and any other that I may have overlooked.)
'board' belongs to Board_t. Hero_t will need a Board_t object to access it. Otherwise how is it supposed to know which board are you accessing? There could be several.
Furthermore, you don't need friendship here, nor should you have it. This is a textbook case of friendship abuse.
It's better to have Board_t check to see if you can move. Something like this would be better:
1 2 3 4 5 6 7
void Hero_t::Move(Board_t board)
{
if( board.CanMove( x, y ) ) // where 'CanMove' is a public member function of Board_t
{
// move the hero to x,y
}
}
The whole point of making members protected/private is that you restrict access to them. If you go around and make every class that is going to use Board_t a friend, it defeats the entire point. You might as well just make the members public.
The concept of encapsulation is hard to grasp for beginners. The idea is you write a class that "works". You expose an "interface" to the outside world with which the class can be used. The outside world doesn't have to worry about how the class works, it can just trust that it does work.
So here, if Board_t is to be properly encapsulated, nothing outside of Board_t should know or care how Board_t works internally. Board_t should just make sure that it does whatever it does its own way, and communicates with other classes (Peg_t, Hero_t) through a simplified interface.
There are many benefits of this:
1) If When bugs surface, they're easier to find and fix. If Board_t is the only one messing with Board_t's stuff, then when a problem happens in Board_t you know right where to look (in Board_t). If everyone and their mother is messing with Board_t's members, then it's a lot harder to know where the problem is and you have to scour your whole program looking for the bug.
2) It makes it easier to change how Board_t works later. If you decide you want to change how Board_t works in order to add new functionality, just change Board_t and keep the interface the same. All you other code can still work just fine. However if all your other code is messing with Board_t's internals, then if you change Board_t you have to go back and change all those other areas as well.
3) It makes your class easier to use.
Especially in this case, since Board_t is apparently managing its own memory (Board_t::board). Having outside code mess with its members is a recipe for disaster.
Keep everything Board_t related inside Board_t. Don't give it friends unless they're really needed (read: they won't be needed for this kind of class, so just don't do it).