简体   繁体   English

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

[英]How to reference derived objects in a vector of pointers to base class objects?

I'm trying to build a chess game in C++. 我正在尝试用C ++构建国际象棋游戏。

I have a base class gamePiece and a derived class rook. 我有一个基类gamePiece和一个派生类菜鸟。 My original idea was to create a vector of gamePiece objects and insert all of the different types of gamePieces (rooks, queens, pawns) inside there. 我最初的想法是创建一个gamePiece对象的向量,并在其中插入所有不同类型的gamePieces(老虎,皇后,典当)。 As I found out in my last question, I can't do that -- the gamePiece vector only takes base class (ie gamePiece) objects. 正如我在上一个问题中发现的那样,我无法做到这一点-gamePiece向量仅接受基类(即gamePiece)对象。

However, smart pointers and other techniques were suggested. 但是,建议使用智能指针和其他技术。 I will try that soon. 我会尽快尝试。

But I'm still curious as to why the technique below won't work. 但是我仍然对以下技术为什么行不通感到好奇。 What if I instead create a vector of pointers to gamePieces, and then attempt to store pointers to my derived objects inside that vector? 如果我改为创建一个指向gamePieces的指针的矢量,然后尝试将指向我的派生对象的指针存储在该矢量中怎么办?

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

For example, suppose I insert a pointer to a rook object inside the above vector at the first location. 例如,假设我在上述向量中的第一个位置插入了指向rook对象的指针。 Initially what I thought might work was this strategy: 最初,我认为可行的策略是:

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

The constructors appear to run fine, everything initializes. 构造函数似乎运行良好,一切都初始化了。 But when it comes time to display the values of the data members onscreen with cout, the variables appear to be empty/unitialized. 但是,当需要使用cout在屏幕上显示数据成员的值时,变量似乎是空的/单位化的。 It's like they disappeared. 就像他们消失了一样。

My second crack at it was to try to dynamically cast the rook pointer to a gamepiece pointer before inserting it in the vector, like this. 我要解决的第二个难题是尝试将rook指针动态地转换为游戏指针,然后再将其插入向量中。

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

But that yielded the exact same output as above. 但这产生了与上述完全相同的输出。 Empty/Unitialized variables. 空/单元化变量。

On my third attempt, I took a step back and tried a simpler operation. 在第三次尝试时,我后退一步,尝试了一个更简单的操作。 Here, I tried to insert a pointer to a gamePiece in the vector instead of a pointer to a rook. 在这里,我试图在向量中插入一个指向gamePiece的指针,而不是指向一个rook的指针。

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

There were issues with even this third operation-- Only some the variables I initialized in the constructor were retained when I attempted the display operation: 甚至第三个操作都存在问题-尝试显示操作时,仅保留了我在构造函数中初始化的一些变量:

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

More specifically, the ints, and the char were retained and displayed properly. 更具体地说,整数和字符保留并正确显示。 But the strings were empty and disappeared. 但是琴弦是空的,消失了。

Anyone have any ideas as to why my strategy isn't working? 有人对我的策略为何行不通有任何想法吗?

You're problem is that you're taking the address of a temporary object and storing it in your std::vector , then that object is destroyed and you're left pointing at an invalid object. 您的问题是,您要获取一个临时对象的地址并将其存储在std::vector ,那么该对象将被销毁,而您将指向无效的对象。

rook(1, "Rook", 'A', 1, "White", "Up") constructs a temporary rook object, which you take the address of with & and push_back it into vectorOfPointersToGamePieces . rook(1, "Rook", 'A', 1, "White", "Up")构造一个临时的rook对象,您可以使用&接收其地址并将其push_backvectorOfPointersToGamePieces That temporary rook is gone by the end of the line and the pointer in vectorOfPointersToGamePieces is left dangling. 该临时rook由线到底去了哪里,并在指针vectorOfPointersToGamePieces是左晃来晃去。 Doing pretty much anything with that pointer will result in undefined behaviour. 用该指针执行几乎任何操作都会导致未定义的行为。

You'll probably need to dynamically allocate your rook object like so: 您可能需要像这样动态分配您的rook对象:

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

However, you'll need to make sure you delete it when you're done with it. 但是,您需要确保在完成操作deletedelete This is why people told you to use std::shared_ptr (or std::unique_ptr ). 这就是为什么人们告诉您使用std::shared_ptr (或std::unique_ptr )的原因。 If you had a std::vector<std::shared_ptr<gamePiece>> then you could do the above line and never worry about delete ing the object. 如果您有std::vector<std::shared_ptr<gamePiece>>则可以执行上述操作,而不必担心delete该对象。

By the way, naming a std::vector<gamePiece*> as vectorOfPointersToGamePieces seems a bit silly, doesn't it? 顺便说一句,将std::vector<gamePiece*>命名为vectorOfPointersToGamePieces似乎有点愚蠢,不是吗? The name of a variable is supposed to describe what it is at an abstract problem level, not its underlying type. 变量的名称应该描述其在抽象问题级别上的含义,而不是其基础类型。 You'd be better off just calling it gamePieces . 您最好将其gamePieces

You are pushing the address of a temporary object. 您正在推送临时对象的地址。 By the time you retrieve and dereference that pointer, the temporary is no longer valid. 在您检索和取消引用该指针时,该临时项不再有效。

This is undefined behaviour. 这是未定义的行为。

You need the objects to be persistent, either allocate them with new , or else statically create them at a scope which will be valid for the duration you require them. 您需要对象是持久性的,或者给它们分配new ,或者在一个范围内静态创建它们,该范围在您需要它们的持续时间内有效。

Right now you're storing the addresses of temporary objects into your vector. 现在,您正在将临时对象的地址存储到向量中。 As soon as that statement finishes execution, the temporary objects are destroyed, so the pointers are no longer valid. 该语句完成执行后,临时对象将被销毁,因此指针不再有效。 When you try to dereference those pointers, you get undefined behavior. 当您尝试取消引用那些指针时,您会得到未定义的行为。

If you're going to store pointers in your vector, you'll pretty much need to allocate the objects dynamically, such as with new . 如果要将指针存储在向量中,则非常需要动态分配对象,例如使用new In other words, replace: 换句话说,替换为:

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

with: 有:

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

and you'll get defined behavior. 您将获得定义的行为。 Note that I'm not really recommending doing this -- as you've (apparently) already been told, you probably want to use some sort of smart pointer (eg, std::unique_ptr seems reasonable in this case). 请注意,我并不是真的建议这样做-正如您(显然)已经告诉您的那样,您可能想使用某种智能指针(例如,在这种情况下, std::unique_ptr似乎很合理)。 This does get rid of your undefined behavior though -- it just leaves you with the job of managing the memory manually, which is better avoided. 但是,这确实摆脱了您未定义的行为-只是让您承担了手动管理内存的工作,最好避免这样做。

All those attempts create and store pointers to temporary expressions. 所有这些尝试都会创建并存储指向临时表达式的指针。 Then when you try to use the pointer later, you get Undefined Behavior. 然后,当您以后尝试使用指针时,会出现“未定义行为”。

To dynamically create objects instead, use the new keyword (or std::make_shared ). 要动态创建对象,请使用new关键字(或std::make_shared )。 And use std::unique_ptr or std::shared_ptr so you don't have to worry about half of the hundred things that commonly go wrong when you're learning pointers. 并使用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") );

Since there is a small, fixed number of pieces, just create 'em. 由于数量少且数量固定,因此只需创建它们即可。 Then put their addresses into the vector. 然后将其地址放入向量中。 No need for smart pointers. 无需智能指针。

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.

相关问题 制作基类指针的向量并将派生类对象传递给它(多态) - Making a vector of base class pointers and pass Derived class objects to it (Polymorphism) 指向包含基类和派生类 class 对象的指针的向量 - 访问派生类特定变量 - Vector of pointers to base class containing base and derived class objects - accessing derived-class specific variables 使用基类指针派生类对象 - Using Base Class Pointers to Derived Class Objects 通过指向基类对象的指针来操作派生类对象的指针 - Manipulating with pointers to derived class objects through pointers to base class objects 如何取消引用存储在智能指针向量中的派生类对象? - How to dereference derived class objects stored in a vector of smart pointers? 将具有映射的抽象基类派生的对象存储在基类指针的向量数组中 - Storing a objects derived from an abstract base class with maps in a vector array of base class pointers 具有派生对象的基类的std :: vector - std::vector of Base class with Derived objects 从指向基类对象的指针向量调用派生类的唯一功能 - Invoke unique functions of derived classes from a vector of pointers to base class objects 在C ++中区分基本指针向量中的派生对象 - Differentiate between derived objects in vector of base pointers in C++ 创建基类对象的向量并将派生类对象存储在其中 - Create a vector of base class objects and store derived class objects within
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM