如何在指向基类对象的指针向量中引用派生对象?

时间:2013-02-18 21:42:18

标签: c++ inheritance vector

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

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

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

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

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

例如,假设我在上面的向量中插入一个指向rook对象的指针 第一个位置。最初我认为可行的是这个策略:

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的指针,而不是指向车的指针。

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

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

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

更具体地说,int和char被保留并正确显示。但是字符串是空的并且消失了。

任何人都有任何想法为什么我的策略不起作用?

5 个答案:

答案 0 :(得分:0)

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

这是未定义的行为。

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

答案 1 :(得分:0)

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

rook(1, "Rook", 'A', 1, "White", "Up")构建一个临时rook对象,您可以将&push_back的地址转换为vectorOfPointersToGamePieces。那个临时的rook在行的末尾消失了,vectorOfPointersToGamePieces中的指针悬空了。使用该指针执行任何操作都会导致未定义的行为。

您可能需要动态分配rook对象,如下所示:

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

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

顺便说一句,将std::vector<gamePiece*>命名为vectorOfPointersToGamePieces似乎有点傻,不是吗?变量的名称应该描述它在抽象问题级别的内容,而不是其底层类型。你最好只叫它gamePieces

答案 2 :(得分: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在这种情况下似乎是合理的)。这确实消除了你未定义的行为 - 它只是让你完成了手动管理内存的工作,这是更好的避免。

答案 3 :(得分:0)

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

要动态创建对象,请使用new关键字(或std::make_shared)。并使用std::unique_ptrstd::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));

OR,

vector<std::shared_ptr<gamePiece>> vectorOfPointersToGamePieces;
vectorOfPointersToGamePieces.push_back(
  std::make_shared<rook>(1, "Rook", 'A', 1, "White", "Up") );

答案 4 :(得分:0)

由于存在少量固定数量的碎片,因此只需创建它们即可。然后将他们的地址放入向量中。不需要智能指针。

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

std::vector<game_piece*> whites_pieces;
whites_pieces.push_back(&white_kings_rook);