0

AoA, I am making a console game of chess, But I am stuck at polymorphism, below is the classes and functions definitions /* old Part //Base Class

class Piece         /*Parent class */
{
protected:
    Position* pCoord;
    std::string color;
    char symbol;
public:
    Piece(Position* Coord,std::string Color,char symbol);
    Position GetCurrentPos();
    std::string GetColor();
    void SetColor(std::string color);
    void Draw();
    virtual bool SetPos(Position* newPos){MessageBox(NULL,L"Virtual Running",L"Error",MB_OK); return true;};
    virtual ~Piece();
};

/* Inherited classes */
//Child classes
class Pawn: public Piece
{
private:
    std::vector<Position>* allowPos;
public:
    Pawn(Position* Coord,std::string Color,char symbol);
    ~Pawn();
    std::vector<Position>* GetThreatendFields();
    bool isValidMove(Position* newPos);
    bool SetPos(Position* newPos);
};
//Child classes
class Bishops: public Piece
{
private:
    std::vector<Position>* allowPos;
public:
    Bishops(Position* Coord,std::string Color,char symbol);
    ~Bishops();
    std::vector<Position>* GetThreatendFields();
    bool isValidMove(Position* newPos);
    bool SetPos(Position* newPos);
};
//Here is the implementation of child class function SetPos


   bool Pawn::SetPos(Position* newPos)
{
    bool isSet = false;

    this->pCoord = new Position();
    this->pCoord = newPos;
    isSet = true;
    MessageBox(NULL,L"Child function running",L"Yuhuu!",MB_OK);

    return isSet;
}


 class ChessBoard
{
private:
    Position ptr;       //dummy
    int SelectedPiece;
    vector<Piece> pPieceSet;
    bool isSelected;
public:
    ChessBoard();
    ~ChessBoard();
    void ShowPieces(Player *p1,Player *p2);
    void Draw();
    void MouseActivity();
    void Place(Piece& p);
};

//it just shows the peices acquired from player objects..dummy vector pointer
void ChessBoard::ShowPieces(Player* p1,Player* p2)
{
    std::vector<Piece>* vPiece = p1->GetPieces();
    for( int i=0;i<vPiece->size();i++ )
    {
        Piece& piece = vPiece->at(i);
        Place(piece);
        piece.Draw();
    }
    vPiece = p2->GetPieces();
    for( int i=0;i<vPiece->size();i++ )
    {
        Piece& piece = vPiece->at(i);
        Place(piece);
        piece.Draw();
    }
}
*/
/*new part

I did what you say

Player::std::vector<Piece*> *vPieceSet;
Player::Player(int turn)
{
    this->turn = turn%2;    
    this->vPieceSet = new std::vector<Piece*>;
}
void Player::Initialize()       //Initial and final ranges for position
{
    //Initialization of pieces to their respective position
    Position pos;
    Piece *pPiece;
    if( this->turn == 0 )
    {
        this->SetName("Player 1");

        for( int i=8;i<16;i++ )
        {
            pos.SetPosition(i);
            Pawn pPawn(&pos,"blue",'P');
            pPiece = &pPawn;

            this->vPieceSet->push_back(pPiece);
        }
   //other classes same as above
}

It runs fine at initialzation function(stores all classes fine) but when use function to get the vector object

std::vector<Piece*>* Player::GetPieces()
{
    std::vector<Piece*>* tPieces = this->vPieceSet;
    return tPieces;
}

//In main.cpp
it doesnot return the vector object
        Player p1(0),p2(1);
    p1.Initialize();
    p2.Initialize();      //initialization done perfectly while debugging

    vector<Piece*> *obj = p1.GetPieces();   //returns garbage
    Piece* pObj = obj->at(0);               //garbage

    cout<<pObj->GetColor();    //  garbage

*/new part

Sounds like I have another problem!

Saad Abdullah
  • 2,252
  • 3
  • 29
  • 42
  • 1
    Can you post the implementation of one of these SetPos methods? And also, the code that calls it? – Medinoc Oct 04 '13 at 13:52
  • How are you creating the child objects? How are you calling SetPos? – doctorlove Oct 04 '13 at 13:52
  • 7
    I'm betting on some slicing problem. – Medinoc Oct 04 '13 at 13:52
  • can you show how you initialize objects and call setPos? – billz Oct 04 '13 at 13:54
  • I am storing all pieces objects in vector like this, in another class chessboard(the main class in which I am doing all stuff) Pawn pPawn; //pPawn initialization Piece* pPiece = &pPawn; //ChessBoard class function this->Place(pPiece); //which places the pPiece object in vector – Saad Abdullah Oct 04 '13 at 13:58
  • 4
    Just looking at your code there are pointers being used in lots of places where I can't see any reason why you would want to use a pointer. But I'm guessing from your error that the one place you needed to use pointers you didn't. – john Oct 04 '13 at 13:58
  • @SaadAbdullah what does this vector of pieces look like, how have you declared it? – john Oct 04 '13 at 14:01
  • I think virtual methods (OOP polymorphism) should be avoided in consoles, due to cache-related performance issues. Consider [this](http://research.scee.net/files/presentations/gcapaustralia09/Pitfalls_of_Object_Oriented_Programming_GCAP_09.pdf) – Manu343726 Oct 04 '13 at 14:02
  • 2
    http://www.cplusplus.com/doc/tutorial/polymorphism/ You might consider making your base class abstract, and that virtual function abstract, such that when you have a pointer of type Piece and make the function call, we know we have to go looking for the specific implementation of Pawn or Bishop rather than using the parent implementation. – Denise Skidmore Oct 04 '13 at 14:03
  • I can bet he calls virtual method from child constructors. – kvv Oct 04 '13 at 14:09
  • I have updated the answer with all possible classes as I can.If anyone need the whole code, I am ready to give you the link of dropbox... or need any other details, just ask me! :( – Saad Abdullah Oct 04 '13 at 14:13
  • @kw : I am calling virtual method from chessboard class, you can see above – Saad Abdullah Oct 04 '13 at 14:15
  • @Saad Abdullah: vector pPieceSet; hmmm, mb I'm wrong, but I think it should be pointers in your container? – kvv Oct 04 '13 at 14:23
  • @kw:I am not making it dynamic object, or not treating it like dummy pointer or pass by reference, it is where I store all Pawns, bishops,knights classes object originally and all other classes accesses it by reference(&) , it is some problem with virtual function as far as I think, because everything is running fine, the problem is in mouseActivity function, somewhere in this->pPieceSet.at(i).SetPos(&obj); because it calls virtual function instead of derived class function – Saad Abdullah Oct 04 '13 at 14:32

2 Answers2

7

When you use polymorphism, what you are really trying to do is instantiate an object of derived type and call the methods on that object through a pointer or reference to the base object.

class Foo
{
public:
  virtual void DoIt () { cout << "Foo"; }
};

class Bar
:
  public Foo
{
public:
  void DoIt () { cout << "Bar"; }
};

int main()
{
  Foo* foo = new Bar;
  foo->DoIt(); // OUTPUT = "Bar"
  Foo& fooRef = *foo;
  fooRef.DoIt(); // OUTPUT = "Bar"
}

In order for this to work, you need to use either a pointer or a reference to the object. You can't make a copy of the object using a the base class. If you make a copy, you will slice the object.

int main()
{ 
  Foo* foo = new Bar;
  foo->DoIt(); // OK, output = "Bar"
  Foo fooCopy = *foo;  // OOPS!  sliced Bar
  fooCopy.DoIt(); // WRONG -- output = "Foo"
}

In your code, the Piece class is intended to be polymorphic, and in your ChessBoard class you have a vector of this class:

class ChessBoard
{
private:
    vector<Piece> pPieceSet;
};

Since this is a vector of the Piece object itself, and not a pointer-to-Piece, anything you put in here will be sliced. You need to change pPieceSet to be a vector of pointers-to-Piece:

vector <Piece*> pPieceSet;

You have further problems in Initialize, which need to be refactored anyway. For one thing, you have another vector of Piece objects, and there are two problems here. First, it needs to be a vector of pointers, and second, why do you need another vector at all when there is already one associated with the ChessBoard? I didn't thouroughly examine your code so maybe you do need it, but this seems like an error. There should probably just be one collection of pieces, in the ChessBoard.

In your Initialize method:

Piece *pPiece;
// ...
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
vPieceSet.push_back(*pPiece);

There are a couple of problems. One, you are pushing back a sliced copy of the Piece, which will be fixed when you change your vector to store pointers. Second, if you just change this like so:

Piece *pPiece;
// ...
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
vPieceSet.push_back(pPiece); // <-- not dereferencing

You will have a new problem because you'll be storing the pointer to a local (automatic) variable. Best is to do this:

Piece* pPiece = new Pawn (...);
// ...
vPieceSet.push_back (pPiece);

Please don't forget to delete everything you new. This is best handled by using smart pointers rather than raw pointers. In C++03 we have auto_ptr, but those can't go in a vector. Instead you'll need to use Boost or something else, or just store raw pointers. In C++11, we now have unique_ptr (preferred) and shared_ptr, which can go in to a vector.

In C++11, the best solution here is to have a vector declared as:

vector <unique_ptr <Piece> > pPieceSet;

...unless you have some compelling need to use shared_ptr instead.

Community
  • 1
  • 1
John Dibling
  • 99,718
  • 31
  • 186
  • 324
2

As others have mentioned, it is a slicing issue, and the issue is created here:

class Player
{
private:
    std::string pName;
    std::vector<Piece> vPieceSet;  // <-- This is your problem
    int turn;
public:
    Player(int turn);
    ~Player();
    void Initialize();
    std::string GetName();
    void SetName(std::string Name);
    int GetTurn();
    std::vector<Piece>* GetPieces();
};

You are storing them in the vector as instances of Piece, which is slicing off the details of the piece (e.g. the Bishop implementation). You should modify it to something like:

class Player
{
private:
    std::string pName;
    std::vector<Piece*> vPieceSet;  // or better, use a smart pointer wrapper
    int turn;
public:
    Player(int turn);
    ~Player();
    void Initialize();
    std::string GetName();
    void SetName(std::string Name);
    int GetTurn();
    std::vector<Piece*> GetPieces(); // note this change as well
};

With your additional question/edit, you are getting another unrelated problem:

void Player::Initialize()       //Initial and final ranges for position
{
    Position pos; // position is declared inside the scope of Initialize
    Piece *pPiece;
    if( this->turn == 0 )
    {
        this->SetName("Player 1");

        for( int i=8;i<16;i++ )
        {
            pos.SetPosition(i);
            Pawn pPawn(&pos,"blue",'P'); // you are passing the address of position to the Pawn, and Pawn is within the scope of this loop
            pPiece = &pPawn; // you are storing the address of the Pawn

            this->vPieceSet->push_back(pPiece);
        }
// Pawn is now out of scope and pPiece points to the memory location Pawn *used* to be at (but will likely be overwritten soon).
// As soon as this function returns, you have the same problem with pos
}

You need to allocate those variables on the heap (hence the reason we suggested smart pointer wrappers).

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • Maybe the problem lies here, for this, I have to change the code from A to Z, I will reply back after couple of minutes thanks for your response! :) – Saad Abdullah Oct 04 '13 at 14:38
  • plz see the /*new part of my question- */ – Saad Abdullah Oct 04 '13 at 15:09
  • You are attempting to store the address of variables that are no longer in scope. That is another question entirely, but I've addressed it somewhat. You should start with a more simple project to understand pointers and memory access before jumping into a larger project. – Zac Howland Oct 04 '13 at 15:24
  • :: I have corrected that problem :) by using unique_ptr – Saad Abdullah Oct 04 '13 at 15:28
  • @SaadAbdullah `unique_ptr` will not fix your attempt to access memory that is no longer in scope. `Position p` puts an object of type `Position` on the stack. If you take the memory location of p (e.g. `&p`), it is only valid as long as `p` is not destroyed. Since it is on the stack, when it goes out of scope its destructor is called and the memory is available for something else. If you continue to point to it, it is a dangling pointer ... which is why you are seeing garbage. – Zac Howland Oct 04 '13 at 15:45
  • Thank You! all guyz, I have solved the problem by the answer given above, and by using unique_ptr – Saad Abdullah Oct 04 '13 at 19:13