views:

253

answers:

9

Suppose I have a class with 2 static functions:

class CommandHandler
{
public:
  static void command_one(Item);
  static void command_two(Item);
};

I have a DRY problem where I have 2 functions that have the exact same code for every single line, except for the function that it calls:

void CommandOne_User()
{
  // some code A

  CommandHandler::command_one(item);

  // some code B
}

void CommandTwo_User()
{
  // some code A

  CommandHandler::command_two(item);

  // some code B
}

I would like to remove duplication, and, ideally, do something like this:

void CommandOne_User()
{
  Function func = CommandHandler::command_one();

  Refactored_CommandUser(func);
}

void CommandTwo_User()
{
 Function func = CommandHandler::command_one();

 Refactored_CommandUser(func);
}

void Refactored_CommandUser(Function func)
{
  // some code A

  func(item);
}

I have access to Qt, but not Boost. Could someone help suggest a way on how I can refactor something like this?

+4  A: 

I posted a question very similar to this and this was the explanation I got:

Function Pointers

And here is the link to the question I posted: http://stackoverflow.com/questions/2792294/function-callers-in-c

thyrgle
It would be helpful if you added the link to the question you posted.
David Rodríguez - dribeas
Ok, there you go.
thyrgle
A: 

Static member functions can be passed simply as function pointers.

Non-static can be passed as member-function pointer + this.

EFraim
+6  A: 

You could use function pointers:

// type of the functions
typedef void Function(Item);

void CommandOne_User() {
  // function pointer
  Function *func = CommandHandler::command_one;
  Refactored_CommandUser(func);
}

void CommandTwo_User() {
  // can also be used directly, without a intermediate variable
  Refactored_CommandUser(CommandHandler::command_two);
}

// taking a function pointer for the command that should be executed
void Refactored_CommandUser(Function *func) {
  // calling the funcion (no explicit dereferencing needed, this conversion is
  // done automatically)
  func(item);
}
sth
A: 
void Refactored_CommandUser(static void (*func)(Item))
{
    // some code A

    func(item);

    // some code B
}

void CommandOne_User()
{
    Refactored_CommandUser(&CommandHandler::command_one);
}

void CommandTwo_User()
{
    Refactored_CommandUser(&CommandHandler::command_two);
}
FredOverflow
A: 

see this please http://www.newty.de/fpt/fpt.html

renick
-1 Thats exactly what I put! Stealer!
thyrgle
you just were a bit faster thats all. cheer up.
renick
+1 to balance the universe
gruntled
@gruntled: LOL. +1 for balancing the universe.
ShaChris23
Not every day you get to balance the universe. Just think, I could click one of these up or down buttons... *and upset the balance of the universe*.
Thanatos
@mrl33t: Ehhh... Technically, but, my page would surely lead to his and in my opinion is too close, but, I guess your technically right. And, it seems no one agrees so I will not fight it any further.
thyrgle
@thyrgle: small advice: avoid downvoting just because of the answer being the same. In many cases it is just a problem of timing, and even if it is not chances are that by the time the second answer comes your answer would already have some upvote and would be pushed to the top, where it will get more votes. Downvoting a correct answer will actually have the opposite effect, someone will *balance the universe* and the net effect is giving reputation. Remember, stackoverflow is about providing correct answers, it is **not** a competition.
David Rodríguez - dribeas
@David Rodíguez: Ok, I'll take that advice next time. I cannot take back what I did either unless the question is edited or something though.
thyrgle
+2  A: 

I can think of two ways.

  1. The C style way: pass the function to be called in as a function pointer.
  2. The C++ way: create a base class that implements your code and replace the called function with a virtual method. Then derive two concrete classes from the base class, each one implementing the virtual function differently.
Jay
+1 for mentioning C++ way.
ShaChris23
@Sha: How is OO the C++ way? If anything, templates should be the C++ way :)
FredOverflow
@FredOverflow: ;-p I'm simply quoting Jay.
ShaChris23
C++ is the language of the many ways... a plain free-function pointer is C++, as passing a functor, or templated functors like `boost::function/std::function` with binders... pick your choice :)
David Rodríguez - dribeas
+6  A: 

Besides the C way (passing a function pointer) or the C++ way mentioned by Jay here there is the other (modern) c++ way with boost or with a compiler with c++0x support:

void Refactored_CommandUser( boost::function<void (Item)> f ) {
   // alternatively std::function with proper compiler support
}

With the advantage that this encapsulates a functor, and can be combined with boost::bind (or std::bind) to pass in not only free-function pointers that match the signature exactly, but also other things, like member pointers with an object:

struct test {
   void f( Item );
};
void foo( Item i, std::string const & caller );
void bar( Item i ); 
int main() {
   test t;
   Refactored_CommandUser( boost::bind( &test::f, &t, _1 ) );
   Refactored_CommandUser( boost::bind( foo, _1, "main" ) );
   Refactored_CommandUser( bar ); // of course you can pass a function that matches directly
}
David Rodríguez - dribeas
+1 this is truly the "C++ way" lol. I'm going to try this on my Intel Compiler. I have Boost, just not on the project I'm working on.
ShaChris23
I chose this answer because of its usage of modern language feature. e.g. I knew about function pointer before asking this question, but I wanted to know if there's a "better" way than using function pointer.
ShaChris23
A: 

So inspired by David Roriguez's answer, I tried it out on my own and, yup, it works:

Here's an example (stupid) code of the "modern" way to pass a function as a function parameter:

#include <functional>    
#include <assert.h>

class Command
{
public:
  static int getSeven(int number_)
  {
    return 7 + number_;
  }
  static int getEight(int number_)
  {
    return 8 - number_;
  }
};

int func(std::tr1::function<int (int)> f, int const number_ )
{
  int const new_number = number_ * 2;
  int const mod_number = f(new_number);
  return    mod_number - 3;
}


int main()
{
  assert( func(Command::getSeven, 5)  ==  14 );
  assert( func(Command::getEight, 10) == -15 );

  return 0;
}

I tried this on VS2008 with Intel C++ Compiler 11.1 with C++0X support on (don't know if C++0x support is really needed since it's in TR1).

ShaChris23
+2  A: 

Another way to do this if you don't have access to tr1 or boost, is just to use function template. It's quite simple and obviously a C++ way.

Here's a compilable example similar to yours:

#include <iostream>
using namespace std;

class CommandHandler
{
public:
   static void command_one(int i) { cout << "command_one " << i << endl; }
   static void command_two(int i) { cout << "command_two " << i << endl; }
};

template <typename Func>
void CommandCaller(Func f)
{
   f(1);
}

int main()
{
   CommandCaller(&CommandHandler::command_one);
   return 0;
}
ryaner
This is another good example. Thanks!
ShaChris23