The new forums will be named Coin Return (based on the most recent vote)! You can check on the status and timeline of the transition to the new forums here.
The Guiding Principles and New Rules document is now in effect.

C++ Coding problem

RendRend Registered User regular
edited September 2007 in Help / Advice Forum
So, here's the deal. My program has 2 classes, we'll call them Piece and Space, and one global pointer to an object of type Space.

Class Piece has nothing in the class requiring an object of class Space. Hooray, you can go first!
Class Space has a bunch of methods in it requiring objects of class Piece. I guess you go after class Piece, then!

Everything is aweso- wait... eh? No compiley?
Oh wait, class Piece uses the pointer of type Space. The pointer needs declared before Piece. But it also needs declared after Space, which is a direct reversal in my previous required order.

My question is this:

Can I declase class Space before class a without actually defining its methods or anything, a forward declaration of sorts? I've tried this:

class Space;
Space* pRofl;

class Piece
{zomg stuff!
}
...and methods, wow!...

class Space
{more stuf lulz
}
...and methods...

but it keeps telling me that Space is a struct, which i do not obviously want it to be. The infuriating thing is that it gets rid of all the errors about space not being first, but then generates more about redeclaring and defining my class and how it's a struct and how the compiler enjoys being a douchebag and stuff.

How can i use a forward declaration _successfully_, in this situation?

Rend on

Posts

  • DrFrylockDrFrylock Registered User regular
    edited September 2007
    It's been a while since I wrote C++, but isn't this what .h files are for?

    DrFrylock on
  • RendRend Registered User regular
    edited September 2007
    I tried that, but I can't get it to compile the .h files without having those declarations in there... i mean, I could just not know how to do that. How would make the .h file so that it didn't care about stuff not being declared, when the compiler in my main source code does?

    Rend on
  • SageinaRageSageinaRage Registered User regular
    edited September 2007
    I'm more familiar with C than C++, but doesn't it hold to the 'one file, one class' paradigm? That might be why it keeps thinking one of the classes is a struct.

    SageinaRage on
    sig.gif
  • RendRend Registered User regular
    edited September 2007
    No, you can have as many classes defined as you like. The whole thing would be fine if it weren't for me needing the pointer to the class Space. This is my first foray into Object Oriented Programming using C++, but I do know that you can declare as many classes in one source file as you please.

    Rend on
  • Nova_CNova_C I have the need The need for speedRegistered User regular
    edited September 2007
    Think of it like the compiler 'pastes' the contents of a .h file where the #include appears. The compiler treats it as a single source.

    Anyway, I'm not really understanding what you're trying to do, but isn't it a bad idea to use global variables in a class? Classes are meant to be compartmentalized, the whole idea is that they're separate entities and have their own attributes and functions.

    Nova_C on
  • jotatejotate Registered User regular
    edited September 2007
    You're defining two classes that depend on each other to exist, basically. The problem is that you're telling it that Space is a kind of Piece and Piece is a kind of Space, which doesn't really make sense. It's like defining a Square as a "Rectangle with even sides" and a Rectangle as a "Square with not even sides."

    Look into inheritance classes and see if you can rearrange the classes that way so that one of them is a kind of the other. (Square -> Rectangle with even sides and Rectangle -> Polygon with 4 sides and 90 degree angles Polygon -> etc...)

    It's hard out of context to give you much more than that.

    jotate on
  • RendRend Registered User regular
    edited September 2007
    Thats true, perhaps a bit more information would be in order...

    I am attempting to program Chess from scratch.

    I have objects of type Piece, along with inherited classes of type Piece like Pawn and Bishop, etc, but that all can be called Piece because of their type.
    My board is a 2 dimensional array of pointers, pointers to class Space. Each space has data like its location and a pointer to whoever is on the space, and a bunch of methods such as clear space and such.

    The only reason I made the board global is because it was simpler to do that than to include it in my setupBoard function, since it was at the bottom, and since Piece and Space end up using board[x][y], I end up having to declare it in advance.

    I have just found this online:
    "A forward declaration gives the compiler enough information to let you
    create a pointer or a reference to an object of the forward declared
    type, but not much more than that. It is NOT enough to allow you to
    create objects of that type, and here you've defined the parameter to be
    an object instead of a reference or pointer, so the compiler rejects the
    code. "

    In my code right now, in the Piece class, I use 3 methods which call for the board,

    checkSpace (which will check to see if the supposed space is a valid move)
    checkSpaceHostile (which will check to see if the supposed space is occupied by a hostile piece)
    move (which will work with the board to empty out the space to move to, if occupied, and then move)

    Rend on
  • RendRend Registered User regular
    edited September 2007
    It may just be easier/my only choice to put those methods into the other class and have Piece call them indirectly...

    Rend on
  • Nova_CNova_C I have the need The need for speedRegistered User regular
    edited September 2007
    My suggestion is that you design it thusly:

    Forget having a class space. Simply define your board as x,y co-ordinates. Have a class piece. A piece has a co-ordinate that defines where it is on the board (Say, -1, -1 means it's dead and no longer on the board). All you sub types like say Pawn inherit from Piece. Each sub-type defines how it can move. Then when a move is being checked, search through the co-ordinate locations of each piece to make sure the move is legal.

    Nova_C on
  • RendRend Registered User regular
    edited September 2007
    Then displaying the board would be significantly more difficult, neh?

    Rend on
  • SuckafishSuckafish Registered User regular
    edited September 2007
    Nova_C wrote: »
    My suggestion is that you design it thusly:

    Forget having a class space. Simply define your board as x,y co-ordinates. Have a class piece. A piece has a co-ordinate that defines where it is on the board (Say, -1, -1 means it's dead and no longer on the board). All you sub types like say Pawn inherit from Piece. Each sub-type defines how it can move. Then when a move is being checked, search through the co-ordinate locations of each piece to make sure the move is legal.

    Pretty inefficient, but I think the suggestion to have the piece contain x, y co-ordinates is a good one. I'd do that, but stick with the original idea to have a space class too. So all in all you'd end up with:

    - a 2D array of instances of the space class (where each instance can contain a pointer to the piece occupying it, if needed)
    - instances of the piece class, each containing an x, y index into the 2D space array

    Suckafish on
  • Nova_CNova_C I have the need The need for speedRegistered User regular
    edited September 2007
    Would it? Display a single image of a chessboard. The entire thing is a single sprite. Each piece is it's own sprite = to the size of an individual square on the chessboard. Let's say the top left of the board is space 0, 0 as well as the top left of the square being pixel 0, 0.

    Each square is 30 x 30, so each piece sprite is 30 x 30. If a piece has a co-ordinate of 5,7, then display the piece at pixel location (5 x 30), (7 x 30). No need for a Space object.

    Nova_C on
  • RendRend Registered User regular
    edited September 2007
    Suckafish: Thats what I've currently got, but it doesn't solve the problem at hand. Each use of the board (my array of spaces) in my piece class references space, which is apparently no good if i'm using a forward declaration.

    Maybe i need a new class for these three methods only? That could work.

    Rend on
  • RendRend Registered User regular
    edited September 2007
    Nova_C wrote: »
    Would it? Display a single image of a chessboard. The entire thing is a single sprite. Each piece is it's own sprite = to the size of an individual square on the chessboard. Let's say the top left of the board is space 0, 0 as well as the top left of the square being pixel 0, 0.

    Each square is 30 x 30, so each piece sprite is 30 x 30. If a piece has a co-ordinate of 5,7, then display the piece at pixel location (5 x 30), (7 x 30). No need for a Space object.

    This is a console application, if that clears things up :-P

    I'm too n00b to deal with graphics yet.

    Rend on
  • Nova_CNova_C I have the need The need for speedRegistered User regular
    edited September 2007
    Suckafish wrote: »
    Pretty inefficient, but I think the suggestion to have the piece contain x, y co-ordinates is a good one. I'd do that, but stick with the original idea to have a space class too. So all in all you'd end up with:

    - a 2D array of instances of the space class (where each instance can contain a pointer to the piece occupying it, if needed)
    - instances of the piece class, each containing an x, y index into the 2D space array

    Hmm. I guess what he could do is define Class Piece, without giving it a Space attribute (Kinda odd, but it's friday and I'm winding down). Define Class Space as pointing to an object Piece. Define all your pieces inheriting from Class Piece and give each piece a Space.

    Nova_C on
  • jotatejotate Registered User regular
    edited September 2007
    The class Piece shouldn't need to have anything more than rules for moving. Everything else should be able to be extracted to the Space class, which has a pointer to the Piece that's on it only to reference the possible moves associated with that piece.

    Shouldn't be any reason that you should specifically call the piece itself during game play, you can just reference them through the spaces.

    Edit: Damn you person that walked in my office and delayed my response by 5 minutes!

    jotate on
  • SuckafishSuckafish Registered User regular
    edited September 2007
    Rend wrote: »
    Suckafish: Thats what I've currently got, but it doesn't solve the problem at hand. Each use of the board (my array of spaces) in my piece class references space, which is apparently no good if i'm using a forward declaration.

    Maybe i need a new class for these three methods only? That could work.

    I think we are talking about two different things... I thought Nova's suggestion did not have piece directly pointing to objects of type space.

    class piece
    {
    // index into the board array
    int xPosition, yPosition;
    ...
    }

    class space
    {
    class piece *pCurrentPiece;
    ...
    }

    mainFunc
    {
    class space *boardArray [8][8];
    ...
    }

    Suckafish on
  • TheFishTheFish Registered User regular
    edited September 2007
    It's been 3 years or so since I did any C++, but don't you need semi-colons on your class definitions?
    Rend wrote: »
    class Space;
    Space* pRofl;

    class Piece
    {zomg stuff!
    };
    Piece::Method1() {...}
    Piece::Method2() {...}

    class Space
    {more stuf lulz
    };
    Space::Method1() {...}
    Space::Method2() {...}

    TheFish on
  • RendRend Registered User regular
    edited September 2007
    Yes, but I had those. I solved this problem actually a couple minutes ago, by moving those three members into global functions that accepted a parameter of a pointer to the piece in question, allowing me to position them lower in the code.

    My only problem now is a linker error, undefined reference to the checkMove(int x, int y, int player) function in my abstract Piece class, and I don't know what to look for about this error, since it's a linker one.

    Rend on
  • jotatejotate Registered User regular
    edited September 2007
    You're checking a reference that hasn't been set. If you're setting up something like Piece* whitequeen and then using it later, you need to do it like this:

    Piece* whitequeen = new Piece(arguments);

    ...before you try to look up any values associated with whitequeen.

    jotate on
  • RendRend Registered User regular
    edited September 2007
    jotate wrote: »
    You're checking a reference that hasn't been set. If you're setting up something like Piece* whitequeen and then using it later, you need to do it like this:

    Piece* whitequeen = new Piece(arguments);

    ...before you try to look up any values associated with whitequeen.

    Piece has a function called checkMove... this is really the only reason I even need the class, so that all the types of pieces, ie, queen, pawn, etc, can all be called one name and I dont have to know what type of piece it is before I try to check whether or not it can move to a certain space.

    However, my linker error said there is an undefined reference to this function in my abstract Piece class.

    Rend on
  • TheFishTheFish Registered User regular
    edited September 2007
    How are you defining checkMove within Piece?

    iirc you should have Piece::checkMove(...) = 0;

    TheFish on
  • RendRend Registered User regular
    edited September 2007
    declaration:

    virtual bool checkMove(int x, int y, int player);

    definition:
    not defined. Does not need to be defined as it is virtual and abstract, though it should be noted that I have tried averting this error by defining it as such:

    bool Piece::checkMove(int x, int y, int player)
    {
    }

    since there is no logic to checkMove for a generic piece.

    Rend on
  • .:Orion.:Orion Registered User regular
    edited September 2007
    Rend wrote: »
    declaration:

    virtual bool checkMove(int x, int y, int player);

    definition:
    not defined. Does not need to be defined as it is virtual and abstract, though it should be noted that I have tried averting this error by defining it as such:

    bool Piece::checkMove(int x, int y, int player)
    {
    }

    since there is no logic to checkMove for a generic piece.

    I don't code in C++, but pure virtual methods can just be defined like this (I believe... look it up somewhere :P):

    virtual bool checkMove(int x, int y, int player) = 0;

    Then you don't have to implement them with an empty body.

    You should probably just separate each class in their own file. I don't really understand what you're trying to do with that Space pointer... is pRofl the board?

    .:Orion on
  • His CorkinessHis Corkiness Registered User regular
    edited September 2007
    I have no idea why it would be telling you that Space is a struct. In C++, structs and classes are 100% identical, with the exception that a struct's members default to public, while a classes's members default to private.

    What compiler are you using?

    His Corkiness on
  • RendRend Registered User regular
    edited September 2007
    Yes, pRofl is the array of pointers pointing to each space on the board

    Rend on
  • His CorkinessHis Corkiness Registered User regular
    edited September 2007
    Could you post the actual code? It might just be a syntactical error, not the arrangement of your code.

    His Corkiness on
  • AeroAero Registered User regular
    edited September 2007
    A quick glance at your original idea sounded like circular reference, and it seems like you changed your code so you didn't have to use it. But as I didn't notice anyone else mention how to do this properly:

    You have two classes, who need each other's definitions to exist properly, so

    class A;
    class B;

    class A {
    B* myFriendB;
    //function declerations, etc

    // if a function requires stuff from B, merely declare the function, without defining it, ie:
    bool playWithB(int variable1);
    // otherwise just do it normally:
    void sayHi() { std::cout << "Hi!"; };

    };

    class B {
    A* myFriendA;

    int myNumber;

    };



    // after you've finished B, using the :: operator, you can now define the functions from A and B that you had toleave blank

    bool A::playWithB(int variable1) {
    std::cout << myFriendA->myNumber;
    myFriendA->myNumber += variable1;

    };

    Aero on
Sign In or Register to comment.