3

I'm trying to create any iterable to store subclass objects in.

I currently am using a vector of pointers to the superclass, but this doesn't seem to allow any of the subclass-specific declarations to be used.

class piece
{
public:
    int foo()
    {
        return 1;
    }
};

class pawn : public piece 
{
public:
    int foo()
    {
        return 2;
    }
};

std::vector<piece*> pieces;
pieces.push_back(new pawn());

pieces[0]->foo(); // returns 1 though pieces[0] should be a pawn

The call to pieces[0]->foo() returns 1, when I want it to return 2.

Debugging shows that the "new pawn()" creates a piece pointer, so I get why it doesn't use the pawn function, but I don't know why it isn't a pawn in the first place.

  • 3
    You need to declare your `foo()` method as [`virtual`](https://en.cppreference.com/w/cpp/language/virtual). – Rhathin Jan 22 '19 at 21:13
  • This code does what you asked for, if you want polymorphism, you should Google for `virtual` – JVApen Jan 22 '19 at 21:14
  • You might also want to read about [when to use `virtual` destructors](https://stackoverflow.com/q/461203/1171191). – BoBTFish Jan 22 '19 at 21:14
  • 1
    While the answer to your question may be obvious once you know it, this is definitely something that's hard to search for. You've done an awesome job of giving us a well written question of clean, concise code with your expected behavior and actual behavior. Great first question--I hope we see more from you in the future! – scohe001 Jan 22 '19 at 21:16
  • virtual is exactly what I needed. Coming from Python, there's so much nuance in C++ that I wouldn't know to look for. Thanks! – Colby Peterson Jan 22 '19 at 21:25

1 Answers1

2

This is because your foo method is not virtual. In several other object-oriented languages, all methods are "virtual" by default, but they are not in C++. "Virtual" means that the function to be called is determined at runtime. When you have a non-virtual method, the compiler decides at compile-time which function to call based on static type information.

In this case, since you have a vector of piece, the compiler invariably determines that it should call pieces[0]->piece::foo(), without checking if there is a more refined version of it in a subclass. If you have a virtual method, the compiler determines that it should look into the object to figure out which one to call based on its type. You would to change the declaration of foo in piece and pawn:

  • virtual int foo() in piece;
  • virtual int foo() override in pawn.

See "Why do we need virtual functions in C++?". In the words of Kenneth Worden, "virtual allows the subclass method to be called, even if the object is being treated as its superclass".

zneak
  • 124,558
  • 39
  • 238
  • 307