tags:

views:

65

answers:

2

I'm creating a button class and am having a hard time deciding between 2 solutions.

1) Templatize the Button class and have it take a function object in its constructor to call when the button is pressed. The guy I'm coding with is worried that this will lead to code bloat/thrashing.

2) Create a ButtonAction base class, and there will be a different ButtonAction for each button. Thus the Button class takes a ButtonAction in its constructor to call when the button is pressed.

We've also considered the use of function pointers, but haven't thought it through that thoroughly.

+1  A: 

I'd enumerate the consequences of each alternative, and then decide which option is best for the particular case at hand.

If the template option might (premature worry?) bloat object code, then the polymorphism alternative might make the source code unnecessarily complex.

In the case of templates the compiler will create another Button class for each function object you instantiate it with. This means the product object code will be larger than if you have a single Button class that accepts various action objects through a subclass.

In the case of polymorphism the compiler will generate a single Button class but you will now have another base class to maintain, and you will be forced to subclass it for any new action you add to your collection. In particular you will not be able to use actions that were written before you created the base action class unless you can modify them so they derive from that action class.

The template alternative allows you to use anything at all that conforms to the template's interface. So if you use the template parameter as a function then you can accept anything at all that can be called like a function. This implies you don't even need to consider the alternative of function pointers, since templates allow you to accept function pointers -- and much more.

The polymorphism option implies the compiler knows more about what you're trying to do. In other words, templates come with templates errors.

You can ease some of the template issues if you can find a way to only template Button member-functions, rather than the entire Button class. Take as function parameter an instance of the template so you don't need to explicitly instantiate the template function. Then you win both on some of the template benefits as well as some of the polymorphism benefits.

wilhelmtell
+5  A: 

You could use boost::function<> objects for your actions. This way you don't need any templates and the button class becomes very flexible:

struct Button {
   typedef boost::function<void ()> action_t;
   action_t action;

   Button(const action_t &a_action) : action(a_action) {
   }

   void click() {
      action();
   }
};

This way the class is easy to use with function pointers, functor objects or things like boost::bind:

void dosomething();
Button b1 = Button(&dosomething);

struct SomeAction {
   void operator()() {}
};
Button b2 = Button(SomeAction());
sth
+1, also consider that in many frameworks you can connect more than one action to a single button. If you want to provide that functionality at one point or another, you just need to change your internal type to `boost::signal<void ()>` and call `.connect` instead of assigning the action to the `boost::function<>` object
David Rodríguez - dribeas