I am working on a small project that contains a vector of base class pointers and my question is, is there anyway to tell which derived class is being stored in the container.

for example... we have a base class named creature and two derived classes named, alien and monster.

in code we would have..
std::vector<creature*> creatureList;

creatureList.pushBack(alien);
creatureList.pushBack(monster);

the creatureList contains both aliens and monsters.

now i want to iterate through the creatureList and perform different functions based on whether the object is an alien or a monster.

Is there any way to do this?

I haven't tried something like this yet and I'm pretty new to classes on my own, however I think that the typeid operator would be the right man for the job.

Look at this and give it a try :)

No no no no no don't do that, then you have no hope of disabling RTTI :D. There are other, more serious downsides, like the fact that if you ever change your code to include another subclass, all your code that uses typeid becomes broken.

There is something known as the "visitor" pattern, which is designed to get around this issue. Unfortunately, C++ has horribly syntax and it's really more tolerable in C# and Java. But you get used to it.

It works like this:

class FastConcat {
 public:
  virtual void Visit(FastConcatVisitor& visitor) = 0;
};

class Leaf {
 public:
  std::string* s;
  void Visit(FastConcatVisitor& visitor) {
    visitor.VisitLeaf(*this);
  }
};

class Branch {
 public:
  FastConcat* left;
  FastConcat* right;
  void Visit(FastConcatVisitor& visitor) {
    visitor.VisitBranch(*this);
  }
};

class FastConcatVisitor {
 public:
  void VisitLeaf(Leaf& leaf) = 0;
  void VisitBranch(Branch& branch) = 0;
};

void sumToString(FastConcat& tree, std::string& builder) {
  SumHelper helper(&builder);
  tree.Visit(helper);
}

class SumHelper : public FastConcatVisitor {
  std::string* accumulator;
 public:
  SumHelper(std::string* acc) : accumulator(acc) { }
  void VisitLeaf(Leaf& leaf) {
    *accumulator += leaf.s;
  }
  void VisitBranch(Branch& branch) {
    branch.left->Visit(this);
    branch.right->Visit(this);
  }
};

If you wanted to add a third kind of FastConcat string, you could do so, and then add a third unimplemented function to the visitor. Then you'd get a bunch of compilation errors, telling you all the places you need to fix your code (where you only implement two of the visitor base class's three abstract methods).

These are all working solutions, but why not add a a type-field to the base class?

Example:

/* base Creature class*/
class creature
{
public:
    std::string what_type;
    creature() {what_type = "undefined";}
};

/* derived class alien */
class alien: public creature
{
public:
    alien(){ what_type = "alien"; }
};

/* derived class monster */
class monster: public creature
{
public:
    monster(){ what_type = "monster"; }
};


int main()
{
    monster *cr1 = new monster();
    alien *cr2 = new alien();
  
    std::vector<creature*> creatureList;
    creatureList.push_back(cr1);
    creatureList.push_back(cr2);
    creatureList.push_back(cr2);
    creatureList.push_back(cr1);

    for (int i = 0; i < creatureList.size(); i++)
        cout << "Creature " << i << " is a " << creatureList[i]->what_type << "\n";
    return 0;
}

output:

Creature 0 is a monster
Creature 1 is a alien
Creature 2 is a alien
Creature 3 is a monster

No no no no no don't do that, then you have no hope of disabling RTTI :D. There are other, more serious downsides, like the fact that if you ever change your code to include another subclass, all your code that uses typeid becomes broken.

Thanks for pointing this out - it's good to learn something from someone else's question :)

At a first glance I prefer niek_e solution because it looks plain and clean, but I'll read carefully your code and experiment with it in order to choose.

To the OP: sorry for the bad hint - as I said I'm still a beginner

This article has been dead for over six months. Start a new discussion instead.