的AoA, 我正在制作一个国际象棋的控制台游戏,但我坚持多态,下面是类和函数定义 / *旧部分 //基类
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
* / new part
听起来我有另一个问题!
答案 0 :(得分: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"
}
为了使其工作,您需要使用指针或对象的引用。您无法使用基类创建对象的副本。如果您制作副本,您将slice该对象。
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;
};
由于这是vector
对象本身的Piece
,而不是指向Piece
的指针,因此您在此处放置的任何内容都将被切片。您需要将pPieceSet
更改为指向vector
的{{1}}:
Piece
您在vector <Piece*> pPieceSet;
中还有其他问题,无论如何都需要重构。首先,你有另一个<{em> Initialize
个vector
个对象,这里有两个问题。首先,它需要是Piece
指针,其次,当已经有一个与vector
关联时,为什么还需要另一个vector
?我没有彻底检查你的代码,所以也许你确实需要它,但这似乎是一个错误。 ChessBoard
中可能只有一个作品集。
在ChessBoard
方法中:
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
(首选)和shared_ptr
,可以进入vector
。
在C ++ 11中,这里最好的解决方案是将一个向量声明为:
vector <unique_ptr <Piece> > pPieceSet;
...除非您有一些迫切的需要改为使用shared_ptr
。
答案 1 :(得分: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
}
您需要在堆上分配这些变量(因此我们建议使用智能指针包装器。)