【问题标题】:How to reference derived objects in a vector of pointers to base class objects?如何在指向基类对象的指针向量中引用派生对象?
【发布时间】:2013-02-03 10:38:42
【问题描述】:

我正在尝试用 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();

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

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

【问题讨论】:

    标签: c++ inheritance vector


    【解决方案1】:

    由于零件数量很少且数量固定,因此只需创建它们即可。然后将它们的地址放入向量中。不需要智能指针。

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

    【讨论】:

      【解决方案2】:

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

      rook(1, "Rook", 'A', 1, "White", "Up") 构造一个临时的rook 对象,您将其地址与&amp;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&lt;std::shared_ptr&lt;gamePiece&gt;&gt;,那么您可以执行上述操作,而不必担心 deleteing 对象。

      顺便说一句,将std::vector&lt;gamePiece*&gt; 命名为vectorOfPointersToGamePieces 似乎有点傻,不是吗?变量的名称应该描述它在抽象问题级别上的含义,而不是其底层类型。你最好直接叫它gamePieces

      【讨论】:

        【解决方案3】:

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

        要改为动态创建对象,请使用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));
        

        或,

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

        【讨论】:

          【解决方案4】:

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

          如果您要在向量中存储指针,您几乎需要动态分配对象,例如使用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 在这种情况下似乎是合理的)。不过,这确实消除了您未定义的行为 - 它只是让您手动管理内存,最好避免这样做。

          【讨论】:

            【解决方案5】:

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

            这是未定义的行为。

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

            【讨论】:

              猜你喜欢
              • 2021-05-20
              • 2014-06-16
              • 1970-01-01
              • 2011-11-04
              • 2021-07-02
              • 1970-01-01
              • 2018-10-31
              • 2012-02-05
              • 1970-01-01
              相关资源
              最近更新 更多