我正在下国际象棋,这是练习基本 OOP 的好方法。有一个抽象基类
Piece
以及 King
、Rook
、Pawn
等子类以及 Board
类。
有没有办法在board类中创建多个重载函数,根据参数的子类执行不同的操作?这就是我的意思,在非常简单的类结构中:
class Piece {};
class King : public Piece {};
class Rook: public Piece {};
class Pawn: public Piece {};
class Board {
public:
void move_piece(King piece) {
;
}
void move_piece(Rook piece) {
;
}
void move_piece(Pawn piece) {
;
}
};
int main() {
Board game;
Pawn pawn;
Piece p = pawn;
game.move_piece(p);
}
我已经尝试实现这个,但是当我将一个片段传递给这个重载函数时,它被声明为
Piece
,而不是 Rook
或 Pawn
。这会导致以下错误:
no suitable user-defined conversion from "Piece" to "Pawn" exists
很公平。但我想做的事情有可能实现吗?
如果您知道
Piece
的确切类型,您编写的代码就会起作用。在这种情况下,通过函数的静态多态性就足够了。
问题是
Piece
是多态的(即动态多态),编译器无法自动知道是否调用采用Rook
、Pawn
等的函数。
穷人的解决方案是尝试使用 Piece
向下转型为 dynamic_cast
的每种可能类型,但这违背了多态性的目的。
相反,请考虑移动
Piece
之间的不同之处:
Pawn
可以向前移动)您可以将其实现为抽象虚函数,例如:
enum class MoveType { None, Move, Attack, Promote };
enum class CheckType { None, Check, CheckMate };
struct MoveResult {
MoveType type;
CheckType check;
};
class Piece {
// ...
public:
virtual MoveResult move(Square) = 0;
};
class Pawn : public Piece {
// ...
public:
MoveResult move(Square s) final {
if (/* can't move to square */) {
return { MoveType::None, CheckType::None };
}
if (/* can move forward to the square */) {
if (/* promotion */) {
return { MoveType::Promote, CheckType::None };
}
}
// ...
}
};
所有特定于片段的逻辑现在都包含在
Piece
的每个派生类中,并且 Board
可以实现 move_piece
,而无需了解这些细节:
// important: pass by reference to avoid object slicing
// note: obtain the square from user input before calling this function;
// alternatively, get it from user input in here
void Board::move_piece(Piece& piece, Square s) {
MoveResult result = piece.move(s);
if (result.check == CheckType::CheckMate) {
// victory
}
if (/* other checks */) {
// ...
}
}