1

I was not really sure how to formulate my question, but here is the puzzle I am trying to resolve:

if (config.a)
  myObject = new Object<DummyInterface>();
else
  myObject = new Object<RealInterface>();

so the task is to create a object with a dummy interface if it is specified in config, otherwise use real interface class. How do I declare myObject then? there are couple options, I could have Object class to derive from abstract class without templates: i.e.:

class Base
{
   ...
}

template <class T>
class Object : public Base 
{
...
}

Then I could declare myObject as:

Base* myObject;

But here is the problem: what if my Object class declares a non virtual method:

template <class T>
class Object : public Base 
{
 public:
   T getInterface() { return myInterface;}
 private:
   T myInterface;
}

I cannot call it like this:

myObject->getInterface()

and I cannot do dynamic cast, because I don't know the type until the runtime...

Any suggestions how to get around it? Maybe there is a another solution?

1
  • 4
    Something went wrong if you need to cast interface to implementation. Try to review design of your classes. Commented Aug 19, 2011 at 12:27

3 Answers 3

2

One way around is to use the visitor pattern. This way, your base class may implement a visit() method and your derived instances can override...

For example..

SomeComponent
{
  template <typename T>  // I'm being lazy here, but you should handle specific types
  void handle(T& cInst)
  {
    // do something
  }
};

class Base
{
public:
  virtual void visit(SomeComponent& cComp) = 0;
};

template <class T>
class Object : public Base 
{
public:
  virtual void visit(SomeComponent& cComp)
  { 
    cComp.handle(*this);
  }
};

Now you can do this

SomeComponent c;
Base* obj = new Object<int>;
obj->visit(c);

And c will get the correct type.

Sign up to request clarification or add additional context in comments.

Comments

0
if (config.a)
  myObject = new Object<DummyInterface>();
else
  myObject = new Object<RealInterface>();

This construction is incorrect in terms of the polymorphism. Two template instantiations are two different classes. The best situation is when you have something like that:

template <class T> SomeClass: public SomeBaseClass 
{
};
......... 
SomeBaseClass* myObject;

But it brings you no profit. The simplest and right solution is the virtual functions. The visitor pattern seems useful too.

Comments

0

I actually think that the visitor pattern would be misused here. Instead, this is a classic switch-on-types code smell that is best handled by polymorphism.

When you say "what if one derived class has an additional method to call", that is assuming a specific design. That is not a functional requirement. A functional requirement would be "what if one of the two objects created had to do behavior X during event Y". Why is this different? Because there are a number of ways to implement this that don't require more interface (though maybe more methods).

Let me show an example.

You have your factory

std::map<ConfigValue, Generator> objectFactory_;

That you've registered a bunch of generators for (probably in constructor of class)

RegisterGenerator(configValueA, DummyGenerator);
RegisterGenerator(configValueB, RealGenerator);
...

And at some point you want to create one of those objects.

shared_ptr<Base> GetConfigObject(ConfigFile config)
{
  return objectFactory_[config.a]();
}

And then you want to use the object for handling an event, you can do

void ManagingClass::HandleEventA()
{
  theBaseObjectReturned->HandleEventAThroughInterfaceObject(this);
}

Note how I passed a this pointer. This means if you have one object that doesn't want to do anything (like make that extra behavior call) that your managing class may provide, it doesn't need to use this.

Object<DummyInterface>::HandleEventAThroughInterfaceObject(ManagingClass *)
{
  // just do dummy behavior
}

And then if you want to do something extra (call a new behavior) it can do it through that pointer in the RealInterface

Object<RealInterface>::HandleEventAThroughInterfaceObject(ManagingClass * that)
{
  that->DoExtraBehavior();
  // then dummy - or whatever order
  // you could even call multiple methods as needed
}

That's the basic approach you should always take when dealing with polymorphism. You should never have two different code paths for different types except through calls to virtual dispatch. You should never have two different code blocks, one that calls methods A, B, and C and another that only calls A and D when dealing with a base object, depending on type. Instead, always make the derived objects do the work of figuring out what to do - because they know who they are. If you need to do stuff in the managing object, pass a this pointer for them to work with.

1 Comment

To add a little bit more: if you want that behavior that I mentioned in HandleEventAThroughInterfaceObject to use the type T - you can do that there. If you need to send the type T to ManagingClass, you can send it there (maybe call a template function). Everything you need to do, do it where you know the type information. This is a much more general problem than the visitor pattern is meant to solve. You don't always need to call the manager, you're not building a means of adding more virtual methods, etc. This is just basic polymorphism design.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.