Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array of functions with different signatures

I have this classes:

class Foo
{
    ...
};

class Foo1 : public Foo
{
    ...
};

...

class FooN : public Foo
{
    ...
};

Is it possible to have an array of functions with these kind of signatures:

void f1(Foo1*){}
...
void fN(FooN*){}

Is there any change if these functions are non static member functions instead of regular functions? I don't think this will change something.

Thanks!

like image 216
Mircea Ispas Avatar asked Sep 07 '11 08:09

Mircea Ispas


2 Answers

EDIT alternative non-virtual-function-based solution here.

The type void(*)(Foo*) is not convertible to the type void(*)(Bar*) and for good reason.

You should make all your functions take an Interface* argument and all the FooN should derive from Interface

struct Interface {
    virtual ~ Interface () {}
    // ...
};

struct Foo1 : public Interface {
    // ...
};

struct Foo2 : public Interface {
    // ...
};

void f1 (Interface *);
void f2 (Interface *);

void (*functions)(Interface*) [] = {f1, f2};

functions[0] (new Foo1 ());
functions[0] (new Foo2 ());
functions[1] (new Foo1 ());
functions[1] (new Foo2 ());

The implementations of f1, f2 can check at runtime if their argument is a particular implementation by using dynamic_cast and checking for nullptr. The only way to check at compile time is to make f1 and f2 take specific types and not put them in an anonymous array, but invoke them explicitly.


To answer the second part of your question -- yes it DOES matter if they're non-static member functions because the size of the pointer is not constant

like image 186
spraff Avatar answered Oct 15 '22 04:10

spraff


You could use function objects. See the example below on how to do it yourselve. If you like the idea you should have a look at boost.signal/boost.bind and the c++ 0x counterparts.

class Foo1 {};
class Foo2 {};
class Foo3 {};

void func1(Foo1*) {}
void func2(Foo2*) {}
void func3(Foo3*) {}

class FuncObjBase {
public:
    virtual void operator()() = 0;
};

template <class T>
class FuncObj : public FuncObjBase {
public:
    typedef void (*Funcptr)(T*);
    FuncObj(T* instance, Funcptr funcptr) : m_Instance(instance), m_Func(funcptr) {}
    virtual void operator()() { m_Func(m_Instance); }
private:
   T* m_Instance;
   Funcptr m_Func;
};

int main(int argc, char *argv[])
{
    Foo1 foo1;
    Foo2 foo2;
    Foo3 foo3;
    FuncObjBase* functions[3];
    functions[0] = new FuncObj<Foo1>(&foo1, func1);
    functions[1] = new FuncObj<Foo2>(&foo2, func2);
    functions[2] = new FuncObj<Foo3>(&foo3, func3);
    for(unsigned int i = 0; i < 3; i++) {
        (*functions[i])();
    }
    return 0;
}
like image 2
David Feurle Avatar answered Oct 15 '22 04:10

David Feurle