0

AoA,我正在做一个国际象棋的控制台游戏,但是我被多态性困住了,下面是类和函数定义 /* 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

我照你说的做了

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

*/新部分

听起来我还有另一个问题!

4

2 回答 2

7

当您使用多态性时,您真正想做的是实例化一个派生类型的对象,并通过指针或对基对象的引用调用该对象的方法。

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"
}

为了使其工作,您需要使用指针或对对象的引用。您不能使用基类制作对象的副本。如果您制作副本,您将对对象进行切片

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

在您的代码中,Piece该类旨在是多态的,并且在您的ChessBoard类中,您有一个vector此类:

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

由于 this 是对象本身vector的a Piece,而不是指向- 的指针Piece,因此您在此处放入的任何内容都将被切片。您需要更改pPieceSet为一个vector指向-的指针Piece

vector <Piece*> pPieceSet;

您在 中还有其他问题Initialize,无论如何都需要对其进行重构。一方面,你有另一个对象 ,这里有两个问题。首先,它需要是 a of 指针,其次,当已经有一个与指针关联时,为什么还需要另一个?我没有彻底检查您的代码,所以也许您确实需要它,但这似乎是一个错误。可能应该只有一个集合,在.vectorPiecevectorvectorChessBoardChessBoard

在你的Initialize方法中:

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

有几个问题。一,您正在推回 的切片副本Piece这将在您更改vector存储指针时修复。其次,如果你只是这样改变:

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

您将遇到一个新问题,因为您将存储指向本地(自动)变量的指针。最好这样做:

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

请不要忘记delete你的一切new。这最好通过使用智能指针而不是原始指针来处理。在 C++03 中我们有auto_ptr,但那些不能进入vector. 相反,您需要使用 Boost 或其他东西,或者只存储原始指针。在 C++11 中,我们现在有unique_ptr(首选) and shared_ptr,它可以进入vector.

在 C++11 中,最好的解决方案是将向量声明为:

vector <unique_ptr <Piece> > pPieceSet;

...除非您有一些迫切需要使用它shared_ptr

于 2013-10-04T14:14:56.660 回答
2

正如其他人提到的,这是一个切片问题,问题是在这里创建的:

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();
};

您将它们作为 的实例存储在向量中Piece,这会切掉片段的细节(例如,Bishop 实现)。您应该将其修改为:

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
};

通过您的其他问题/编辑,您会遇到另一个不相关的问题:

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
}

您需要在堆上分配这些变量(因此我们建议使用智能指针包装器)。

于 2013-10-04T14:28:38.573 回答