0

This is what I am trying to do:

class A {
public:
    void(*fPtr)();
};

class B {
    int ib = 2;
public:
    void memf() {
        printf("ib = %i\n", ib);
    }
};

class C {
    int ic = 6;
public:
    void memf() {
        printf("ic = %i\n", ic);
    }
};

int main()
{
    B b;
    C c;
    A a1;
    A a2;
    a1.fPtr = b.memf;
    a2.fPtr = c.memf;
}

Basically a class that has a function pointer. This function pointer can be directed to a normal or member function.

The error I get in Visual Studio however:

Error   C2440   '=': cannot convert from 'void (__thiscall B::* )(void)' to 'void (__cdecl *)(void)'
Error   C2440   '=': cannot convert from 'void (__thiscall C::* )(void)' to 'void (__cdecl *)(void)'    
Error   C3867   'B::memf': non-standard syntax; use '&' to create a pointer to member
Error   C3867   'C::memf': non-standard syntax; use '&' to create a pointer to member

I know this might seem like a duplicate, maybe it is. I failed to use solutions that were recommended like using <functional>.

Can somebody show me how to do it right so I can understand what I was doing wrong? I would also like to know why the standard way doesn't work.

In other words: Correct my code ;) I would really appreciate it.

Piotr Siupa
  • 3,929
  • 2
  • 29
  • 65
GRASBOCK
  • 631
  • 6
  • 16
  • 1
    There is more information about pointer to member functions: https://stackoverflow.com/questions/2402579/function-pointer-to-member-function – Piotr Siupa Dec 16 '18 at 01:29
  • 2
    `a.fPtr` is a pointer to a member of class `A`. `b.memf` and `c.memf` (or, more correctly as the warnings say, `&B.memf` and `&C::memf`) are not pointers to members of class `A`. Pointers to members are specific to their class. There is no way to correct it, unless the class `A` contains members to pointers of class `B` and class `C` - what you're trying to do is flawed. – Peter Dec 16 '18 at 01:33

2 Answers2

2

The easiest way to see why this is going to cause problems is to ask - if you did call the function pointed at by the function pointer, what would the receiver object be? For example, suppose you point at B::memf and then call it through fptr. That function needs to operate relative to a B object so that it can read the value of that B object’s ib field. But there’s no way for us to figure out what B object to use - bad times!

The reason that (nonstatic) member functions are different than free functions is that they have an implicit parameter representing the receiver object, and so when calling that function there needs to be some way to specify what that object is.

The other answers on this site should be able to provide some information about some possible strategies for fixing this issue, but hopefully this sheds some light on what that issue is in the first place.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • Yeah, I understand now. I wonder, is there a way to store variables inside a function? Like static variables inside functions. If I do not misunderstand how they work. Edit: Nevermind that won't work. I have found a way! – GRASBOCK Dec 16 '18 at 11:50
1

Here is a possible solution to your problem: I made a few slight changes, though.

  • 1st - I changed Class A to a Class Template.
  • 2nd - I added a pointer to type <T> as a class member.
  • 3rd - I added an operator()() to A<T> to invoke the function call.
  • 4th - I changed the name of your function pointer and the name of the functions of the other classes just to be consistent.
  • 5th - Instead of using printf(), I used std::cout.

Here is what your modified code looks like: Read the comments to understand how this works.

template<class T>
class A {
private:
    // Need to save a pointer to the class to have a realitive object.
    T* ptrT{ nullptr };
public:
    // Assigns the pointer of the object to this's class's pointer member.
    // Must pass by reference otherwise you will have undefined behavior.
    explicit A( T& t ) : ptrT( &t ) {}

    // Notice the Template Arguments class resolution operator...
    void(T::*func)();

    // The added operator()() to invoke the function call.
    // This could of been any arbitrary member function; 
    // I just chose to use the operator() for demonstration.
    void operator()() {
        (ptrT->*func)();
    }
};

// In class's A & B the only changes here are 
// the names of the function and replacing printf() with cout
class B {
    int ib{ 2 };
public:
    void func() {
        std::cout << ib << '\n';
    }
};

class C {
    int ic{ 6 };
public:
    void func() {
        std::cout << ic << '\n';
    }
};

int main() {
    try {
        B b;
        C c;
        // Changes to A by using templates and passing the object      
        // above to A's explicit constructor
        A<B> a1( b );
        A<C> a2( c );

        // Notice the syntax on how to assign the function pointer.
        a1.func = &B::func;
        a2.func = &C::func;

        // using the operator() to invoke the function pointer.
        a1();
        a2();
    } catch( std::runtime_error& e ) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;    
}

-Output-

2
6
Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • I see how that is working... Thank you for showing me. Though unfortunately (that I have not specified in my question) I can't use normal functions that way. I will need to think about it. – GRASBOCK Dec 16 '18 at 11:47