4

Hello all together,

I'm wondering if you are able to define or instantiate a function for example in the constructor of a class.

Let's say you have this simple class:

class cTest {
public:
    cTest( bool bla );
    ~cTest() {}

    void someFunc() {}
};

cTest::cTest( bool bla ) {
    if( bla ) {
        someFunc = functionBody1;
        // or
        someFunc {
            functionBody1
        };
        // or something different
    } else
        someFunc = functionBody2;
}

if someFunc is an often called function, you could avoid testing whether "bla" was true or not every time the function gets called.

I thought about it and two possible solutions came to my mind:

1) Using inheritance:

#include <iostream>

class iTest {
public:
    virtual void someFunc() = 0;
};

class cTest1 : public iTest {
public:
    void someFunc() { std::cout << "functionBody1\n"; }
};

class cTest2 : public iTest {
public:
    void someFunc() { std::cout << "functionBody2\n"; }
};

2) Using function pointers:

#include <iostream>

class cTest {
public:
    cTest( bool bla );
    ~cTest() {}

    void someFunc();
private:
    void ( cTest::*m_functionPointer )();

    void function1() { std::cout << "functionBody1\n"; }
    void function2() { std::cout << "functionBody2\n"; }
};

cTest::cTest( bool bla ) {
    if( bla )
        m_functionPointer = &cTest::function1;
    else
        m_functionPointer = &cTest::function2;
};

void cTest::someFunc() {
    ( *this.*m_functionPointer )( );
};

In the program where I need this I cannot use inheritance and don't want to use function pointers. So my question is, is there another (elegant) way to do this, e.g. defining the function in the constructor of the class?

Thanks a lot for your answers!

Ullyses
  • 41
  • 2
  • Alternative is to use a switch statement and store an id in the class. – Neil Kirk Aug 19 '14 at 17:35
  • 8
    You might want to read about [`std::function`](http://en.cppreference.com/w/cpp/utility/functional/function), [`std::bind`](http://en.cppreference.com/w/cpp/utility/functional/bind) and [lambda expressions](http://en.cppreference.com/w/cpp/language/lambda). – Some programmer dude Aug 19 '14 at 17:36
  • 1
    C++ supports neither nested functions nor late-binding, so no, function pointers/their equivalents in lambdas/binds are going to be the only way to do what you want (barring some possible template expansion black magic that is probably way more complicated than you want). – aruisdante Aug 19 '14 at 17:36
  • @Neil Kirk as I said, I don't want to use function pointers cause until now I didn't hear much good of them. Inheritance cannot be used in this case. – Ullyses Aug 19 '14 at 17:36
  • They do what you want perfectly and you already have the code written. – Neil Kirk Aug 19 '14 at 17:37
  • Lambda expressions are a little hard to read at first, but are VERY powerful when used properly. Check them out! Functors might also be of use: http://stackoverflow.com/questions/356950/c-functors-and-their-uses – Conduit Aug 19 '14 at 17:38
  • 3
    Why don't you want to use function pointers? There's nothing wrong with them. – Fsmv Aug 19 '14 at 17:38
  • 2
    *"I didn't hear much good about them"*: are there any tangible and objective arguements against them in your case ? You won't gossip dictate your work, will you ? – Christophe Aug 19 '14 at 17:41
  • 1
    Use function pointers. I myself heard much good of them :)... – MichaelCMS Aug 19 '14 at 17:56
  • @Christophe I didn't program for a few months now. Before this break I read somewhere about function pointers (I really don't remember where, sorry). They wrote, that calling functions via function pointers is slower than calling a normal function. Maybe it was a gossip, but it left a bad image of function pointers in my mind. – Ullyses Aug 19 '14 at 17:57
  • @JoachimPileborg Thanks for your answer/suggestions :). I'm going to check out lambda now. Thanks for the links! – Ullyses Aug 19 '14 at 18:02
  • 1
    It won't be any slower than the alternatives. If you need to decide the function at runtime, that has a (small) cost. – Neil Kirk Aug 19 '14 at 18:08
  • It's true that calling a function pointer adds an indirection compared to a direct function call (but it's only one machine instruction more). On the other side, using a virtual does exactly the same. It's just hidden. – Christophe Aug 19 '14 at 18:12

2 Answers2

3

If you don't like function pointers, you could use functions:

#include <functional>

In the private part of your class, instead of defining a function pointer, define a function wrapper:

private:
    std::function<void()> m_function;

You can then initialize this function wrapper dynamically in your constructor with a lambda function:

if (bla)
    m_function = [this]() { std::cout << id << "functionBody1\n";   };
else
    m_function = [this]() { std::cout << id << "functionBody2\n";  };

Note that you should capture [this] in order to be able to accesss to class members.

And change the definition of your someFunc() to:

void cTest::someFunc() {
    m_function();
};

Performance considerations:

If you have performance critical questions, you should do a couple of benchmarks to be sure to choose the right solution. Here in release mode with MSVC2013 on a core i7 what I get for 10 000 000 loops:

15 ms for the function wrapper
31 ms for the function pointer 
16 ms for the traditional if/else in the function body. 

In debug mode (unoptimized), it looks differently with 1766, 625 and 297 respecively.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • 3
    This still uses a pointer, though. It's only hidden in `std::function`. – Walter Aug 19 '14 at 18:13
  • Completely true ! The wrapper may however be more handy to manipulate than raw pointer. I'm however astonished in the benchmark that I just added that function wrapper after optimisation appears more efficient than the pointer version. If anyone has an idea about that.. – Christophe Aug 19 '14 at 18:43
  • @Walter: So? What if you use a `std::vector` somewhere in your program? I doubt you would consider that a hidden double pointer. Thinking of `std::function` in terms of pointers is an implementation-side point of view. – Christian Hackl Aug 19 '14 at 19:10
  • @ChristianHackl I have no problems with pointers, but the OP had. – Walter Aug 19 '14 at 19:35
  • +1 for the benchmark. Would be nice to know the reason for the performance difference. Perhaps under the hood the compiler optimises the function pointer away and implements the `if else`??? – Walter Aug 19 '14 at 19:38
  • @Walter: the OP never explained his exact problem with pointers, which leaves me with the conclusion that it's a very superficial dislike and he's happy with encapsulating them. – Christian Hackl Aug 19 '14 at 19:39
  • When taking this route, it is a good idea to delete the copy/move constructors/assignment operators (or implement them correctly), as the defaulted ones are wrong because of the captured this pointer. – Nevin Aug 19 '14 at 21:23
0

If the function body is set depending on the argument (bla) to the constructor at run-time, then unavoidably you need some indirection, be it a virtual table (when using inheritance) or some sort of function pointer (either explicitly or implicitly via std::function).

And yes, this does have some (usually small) impact on your efficiency. So if the function body is small (and fast to execute) and called often (i.e. performance critical), you may not want to use such a construction (function body depending on a run-time argument).

Walter
  • 44,150
  • 20
  • 113
  • 196