views:

75

answers:

2

Scenario: I have the following defined classes.

class Baseclass { };
class DerivedTypeA : public Baseclass { };
class DerivedTypeB : public Baseclass { };
// ... and so on ...

class Container
{
    list<Baseclass*> stuff;
    list<DerivedTypeA*> specific_stuff;
// ... initializing constructors and so on ...
public:
    void add(Baseclass * b)
    {
        stuff.add(b);
    }
    void add(DerivedTypeA * a)
    {
       stuff.add(a);
       specific_stuff.add(a);
    }
};

class ContainerOperator
{
    Container c;
// ... initializing constructors and so on ...
public:
    void operateOnStuff(Baseclass * b)
    {
        // This will always use "void add(Baseclass * b)" no matter what object b really is.
        c.add(b);
    }
};

// ...

containerOperator.operateOnStuff(new DerivedTypeA());

So, what I want to do is to handle a certain derived class in some special way in Container.

Problem: void add(DerivedTypeA * a) is never called. I'm obviously doing something wrong. What is the correct way of doing what I am trying to achieve here?

+4  A: 

Overload resolution in C++ happens at compile-time, not run-time. The "usual" way to solve problems like this is to use Visitor pattern.

You can reduce the amount of boilerplate copy-paste by implementing Visitor with CRTP. If you use CRTP for Base::accept, you don't need to define it any more in derived classes.

Here is a similar program to yours, but a little simpler:

#include <iostream>

class Base; class Derived;
struct Operation {
  void add(Base *b) {
    std::cout << "Base\n";
  }
  void add(Derived *b) {
    std::cout << "Derived\n";
  }
  void visit(Base *b); // need to define this after Base class

};


struct Base {
  virtual ~Base() {}
  virtual void accept(Operation &o)
  {
    o.add(this);
  }


};

void Operation::visit(Base *b) {
  b->accept(*this);
}

struct Derived : public Base {
  void accept(Operation &o)
  {
    o.add(this);
  }

};



int main() {

  Operation o;
  Base b;
  Derived d;

  Base *ptrb = &b;
  Base *ptrd = &d;
  o.add(ptrb); // These two print "Base"
  o.add(ptrd);
  o.visit(ptrb); // "Base"
  o.visit(ptrd); // "Derived"
}
hrnt
Thanks for explaining! After I managed to wrap my head around the Visitor-pattern (your example code helped a lot!) I managed to get it working :)
Morningcoffee
+2  A: 

You can use RTTI to determine whether the provided object is of the derived type, and if so, call the second add() function.

void add(Baseclass * b)
{
    stuff.add(b);
    DerivedTypeA * a = dynamic_cast<DerivedTypeA *>(b);
    if ( a != 0 ) 
      specific_stuff.add(a);
}

Unlike the visitor pattern this solution violates the Open-Closed Principle, but it's a lot simpler and easier to understand when the number of derived classes do not change or change slowly over time.

Phillip Ngan
I would consider this a hack. I would've used it if it wasn't a core feature in my application with an increasing amount of derived classes.
Morningcoffee