3

Inside a class BaseClass I have a public function:

virtual void Call(){};

Inside of a derived class Archer I have the function:

void Call(){ cout << "whatever" << endl; };

I also have a vector set up:

vector<BaseClass> classes;

wherein I push 3 classes derived from BaseClass. The problem seems (to me, I'm probably wrong) to be that I am calling Call() from a reference to BaseClass even though I push them into the vector through a method like:

BaseClass Player::CharChoice(string character)
{
    if(character == "Archer") return *new Archer();
    else if(character == "Knight") return *new Knight();
    else if(character == "Sorcerer") return *new Sorcerer();
    else cerr << "CHARACTER NOT DEFINED" << endl;
};

for(int c = 0; c < chars.size(); c++)
{
    classes.push_back(CharChoice(chars[c]));
}

If I instead set up a variable such as:

Archer *archer = new Archer();

and call Call(), it works how I would intend. I'm fairly new to C++ and cannot think up a solution to this.

Evan Ward
  • 1,371
  • 2
  • 11
  • 23
  • 1
    Polymorphism only works for pointers and references. But you return `BaseClass` as a copy from `CharChoice`, and you make another copy when you push it to the vector. Each copy slices the object back to a `BaseClass` object. – jogojapan Jul 01 '13 at 02:28
  • 2
    `*new T()` is going to pretty much always be a mistake. Use smart pointers. – GManNickG Jul 01 '13 at 02:53

1 Answers1

4

Much of the value of inheritance is lost when you create an object on the stack instead of the heap. Virtual functions is one of the things that you lose, if you want the virtual function to call the right function you must pass the object as pointer or a reference and use new to create it.

Base * b = new Derived();    // or  
Base & b = * new Derived();  

The vector must store a reference or a pointer.

vector<BaseClass*> classes;
vector<BaseClass&> classes;

By popular demand the easiest way to handle this is std::shared_ptr

vector<shared_ptr<BaseClass>> classes;

One of these would be created like so:

shared_ptr<BaseClass> ptr(new BaseClass);

Basically a shared_ptr will handle the annoying task of memory management

shared_ptr is good if you need multiple ptr's to the same object, if not you can use std::unique_ptr

vector<unique_ptr<BaseClass>> classes;

create like this:

unique_ptr<BaseClass> ptr(new BaseClass);

As you can see the syntax is very similar to shared_ptr so the transition is easy

aaronman
  • 18,343
  • 7
  • 63
  • 78
  • 3
    Given that the question is tagged C++11, I'd find it *very* desirable to have a word about smart pointers in the answer. – jogojapan Jul 01 '13 at 02:34
  • 4
    You want to prefer `unique_ptr` over `shared_ptr`. – Griwes Jul 01 '13 at 12:51
  • @Griwes could you please explain why? – aaronman Jul 01 '13 at 16:22
  • @aaronman, lower performance hit than `shared_ptr`. And proper semantics. If the ownership is unique, always use `unique_ptr`, and, unless explicitly marked so, always assume unique ownership. – Griwes Jul 01 '13 at 16:33
  • @aaronman, no! Ownership has nothing to do with threading; it's about *ownership*, not *accessing* the object. – Griwes Jul 01 '13 at 16:48
  • @Griwes give an example where it would be necessary to have multiple ptrs to the same object – aaronman Jul 01 '13 at 18:20
  • @aaronman, are you serious? "Any object that has a shared ownership". This is the definitive answer to that question; if you still have no clue, you should really go back from answering questions to reading a book. ...also, if you have no idea when shared ownership could be useful, why did you even propose a shared ownership primitive (`shared_ptr`) in the first place? -.-" – Griwes Jul 01 '13 at 19:02
  • @Griwes no need to insult me here, if I wasn't clear my confusion is that generally you can avoid a ptr being owned by more than one object when would it be necessary to have shared ownership – aaronman Jul 01 '13 at 19:58
  • @aaronman, then why did you use `shared_ptr` initially...? huh – Griwes Jul 01 '13 at 20:09
  • @Griwes jogojapan recommended I talk about smart ptr's, which I understand, but I have never used c++11's smart_ptr's so I just picked the first one I found and amended my answer after taking a deeper look – aaronman Jul 01 '13 at 20:12