简体   繁体   中英

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

I'm trying to build a chess game in C++.

I have a base class gamePiece and a derived class rook. 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. As I found out in my last question, I can't do that -- the gamePiece vector only takes base class (ie gamePiece) objects.

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?

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. 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. 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.

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.

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.

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 . That temporary rook is gone by the end of the line and the pointer in vectorOfPointersToGamePieces is left dangling. Doing pretty much anything with that pointer will result in undefined behaviour.

You'll probably need to dynamically allocate your rook object like so:

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. This is why people told you to use std::shared_ptr (or 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.

By the way, naming a std::vector<gamePiece*> as vectorOfPointersToGamePieces seems a bit silly, doesn't it? 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 .

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.

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 . 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). 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 ). 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.

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM