1

我正在尝试用 C++ 构建一个国际象棋游戏。

我有一个基类 gamePiece 和一个派生类 rook。我最初的想法是创建一个 gamePiece 对象的向量,并在其中插入所有不同类型的 gamePieces(车、皇后、棋子)。正如我在上一个问题中发现的那样,我不能这样做——gamePiece 向量只接受基类(即gamePiece)对象。

但是,建议使用智能指针和其他技术。我会尽快尝试的。

但我仍然很好奇为什么下面的技术不起作用。如果我改为创建一个指向 gamePieces 的指针向量,然后尝试将指向我的派生对象的指针存储在该向量中会怎样?

vector<gamePiece *> vectorOfPointersToGamePieces;  
vector<gamePiece *>::iterator itOfPointersToGamePieces;

例如,假设我在上述向量的第一个位置插入一个指向车对象的指针。最初我认为可能有用的是这个策略:

vectorOfPointersToGamePieces.push_back( &(rook(1, "Rook", 'A', 1, "White", "Up")  ) );
itOfPointersToGamePieces=vectorOfPointersToGamePieces.begin();  
( * ( * (itOfPointersToGamePieces))).displayPieceInfo();

构造函数似乎运行良好,一切都初始化了。但是当需要使用 cout 在屏幕上显示数据成员的值时,变量似乎是空的/未初始化的。就像他们消失了一样。

我的第二次破解是尝试在将车指针插入向量之前将其动态转换为游戏指针,就像这样。

vectorOfPointersToGamePieces.push_back( dynamic_cast <gamePiece *> (&(rook(1, "Rook", 'A', 1, "White", "Up")  ) ) );

但这产生了与上面完全相同的输出。空/统一变量。

在我第三次尝试时,我退后一步,尝试了一个更简单的操作。在这里,我尝试在向量中插入指向 gamePiece 的指针,而不是指向 rook 的指针。

vectorOfPointersToGamePieces.push_back( &(gamePiece(1, "Rook", 'A', 1, "White", "Up")) );

即使是第三个操作也存在问题——当我尝试显示操作时,只保留了我在构造函数中初始化的一些变量:

itOfPointersToGamePieces=vectorOfPointersToGamePieces.begin();
( * ( * (itOfPointersToGamePieces))).displayPieceInfo();

更具体地说,整数和字符被保留并正确显示。但弦是空的,消失了。

任何人都知道为什么我的策略不起作用?

4

5 回答 5

1

你的问题是你正在获取一个临时对象的地址并将其存储在你的 中std::vector,然后该对象被销毁并且你指向一个无效的对象。

rook(1, "Rook", 'A', 1, "White", "Up")构造一个临时rook对象,您将 with 的地址&push_back它放入vectorOfPointersToGamePieces. 该临时rook文件在行尾消失了,并且指针处于vectorOfPointersToGamePieces悬空状态。用该指针做几乎任何事情都会导致未定义的行为。

您可能需要rook像这样动态分配对象:

vectorOfPointersToGamePieces.push_back(new rook(1, "Rook", 'A', 1, "White", "Up"));

delete但是,当你完成它时,你需要确保它。这就是为什么人们告诉你使用std::shared_ptr(或std::unique_ptr)。如果您有 astd::vector<std::shared_ptr<gamePiece>>那么您可以执行上述操作,而不必担心delete对象。

顺便说一句,命名 astd::vector<gamePiece*>似乎vectorOfPointersToGamePieces有点傻,不是吗?变量的名称应该描述它在抽象问题级别上的含义,而不是其底层类型。你最好打电话给它gamePieces

于 2013-02-18T21:46:30.663 回答
0

您正在推送临时对象的地址。当您检索并取消引用该指针时,临时地址不再有效。

这是未定义的行为。

您需要将对象持久化,或者使用 分配它们new,或者在一个范围内静态创建它们,该范围在您需要它们的持续时间内有效。

于 2013-02-18T21:46:20.387 回答
0

现在您将临时对象的地址存储到您的向量中。一旦该语句完成执行,临时对象就会被销毁,因此指针不再有效。当您尝试取消引用这些指针时,您会得到未定义的行为。

如果要将指针存储在向量中,则几乎需要动态分配对象,例如使用new. 换句话说,替换:

[your_vector].push_back( &(rook(1, "Rook", 'A', 1, "White", "Up")

和:

[your_vector].push_back(new rook(1, "Rook", 'A', 1, "White", "up"))

你会得到定义的行为。请注意,我并不是真的建议这样做——正如您(显然)已经被告知的那样,您可能想要使用某种智能指针(例如,std::unique_ptr在这种情况下似乎是合理的)。不过,这确实摆脱了您未定义的行为——它只是让您手动管理内存的工作,最好避免这样做。

于 2013-02-18T21:46:45.577 回答
0

所有这些尝试都会创建和存储指向临时表达式的指针。然后当您稍后尝试使用指针时,您会得到未定义的行为。

要改为动态创建对象,请使用new关键字 (or std::make_shared)。并且使用std::unique_ptrorsostd::shared_ptr您不必担心在学习指针时通常会出错的一百件事中的一半。

vector<std::unique_ptr<gamePiece>> vectorOfPointersToGamePieces;
std::unique_ptr<gamePiece> rk( new rook(1, "Rook", 'A', 1, "White", "Up") );
vectorOfPointersToGamePieces.push_back(std::move(rk));

或者,

vector<std::shared_ptr<gamePiece>> vectorOfPointersToGamePieces;
vectorOfPointersToGamePieces.push_back(
  std::make_shared<rook>(1, "Rook", 'A', 1, "White", "Up") );
于 2013-02-18T21:49:43.193 回答
0

由于有少量固定数量的部件,只需创建它们。然后将它们的地址放入向量中。不需要智能指针。

rook white_kings_rook(/* whatever */);
// ...

std::vector<game_piece*> whites_pieces;
whites_pieces.push_back(&white_kings_rook);
于 2013-02-18T22:04:53.797 回答