![](/img/trans.png)
[英]Making a vector of base class pointers and pass Derived class objects to it (Polymorphism)
[英]How to reference derived objects in a vector of pointers to base class objects?
我正在嘗試用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在屏幕上顯示數據成員的值時,變量似乎是空的/單位化的。 就像他們消失了一樣。
我要解決的第二個難題是嘗試將rook指針動態地轉換為游戲指針,然后再將其插入向量中。
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();
更具體地說,整數和字符保留並正確顯示。 但是琴弦是空的,消失了。
有人對我的策略為何行不通有任何想法嗎?
您的問題是,您要獲取一個臨時對象的地址並將其存儲在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
其delete
。 這就是為什么人們告訴您使用std::shared_ptr
(或std::unique_ptr
)的原因。 如果您有std::vector<std::shared_ptr<gamePiece>>
則可以執行上述操作,而不必擔心delete
該對象。
順便說一句,將std::vector<gamePiece*>
命名為vectorOfPointersToGamePieces
似乎有點愚蠢,不是嗎? 變量的名稱應該描述其在抽象問題級別上的含義,而不是其基礎類型。 您最好將其gamePieces
。
您正在推送臨時對象的地址。 在您檢索和取消引用該指針時,該臨時項不再有效。
這是未定義的行為。
您需要對象是持久性的,或者給它們分配new
,或者在一個范圍內靜態創建它們,該范圍在您需要它們的持續時間內有效。
現在,您正在將臨時對象的地址存儲到向量中。 該語句完成執行后,臨時對象將被銷毀,因此指針不再有效。 當您嘗試取消引用那些指針時,您會得到未定義的行為。
如果要將指針存儲在向量中,則非常需要動態分配對象,例如使用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
似乎很合理)。 但是,這確實擺脫了您未定義的行為-只是讓您承擔了手動管理內存的工作,最好避免這樣做。
所有這些嘗試都會創建並存儲指向臨時表達式的指針。 然后,當您以后嘗試使用指針時,會出現“未定義行為”。
要動態創建對象,請使用new
關鍵字(或std::make_shared
)。 並使用std::unique_ptr
或std::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") );
由於數量少且數量固定,因此只需創建它們即可。 然后將其地址放入向量中。 無需智能指針。
rook white_kings_rook(/* whatever */);
// ...
std::vector<game_piece*> whites_pieces;
whites_pieces.push_back(&white_kings_rook);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.