Pracka
Pracka

Reputation: 159

Assign function pointer inside class

I am writing simple experiment code to test out assigning member function of one class to the function pointer who is a member of another class. My sample code did not compile. The compiler gave an error saying: '&': illegal operation on bound member function expression.

I see some people do (&ClassB::printFun) when passing a pointer to a member function. It didn't work for me because printFun is not a static member function. I have also seen people using std::bind. But std library is not a option for me since I will be using this to write kernel mode code. I have being searching for the right way to do this for a while, can someone help me out? Thanks!

using namespace std;

class ClassA
{
public:
    ClassA(void(*callBack)(int));
    void (*funPtr)(int);
};

ClassA::ClassA(void(*callBack)(int))
{
    funPtr = callBack;
}

class ClassB
{
public:
    void printFun(int a)
    {
        cout << a << endl;
    }
};

int main()
{
    ClassB classB;
    ClassA classA(&classB->printFun);
    classA.funPtr(5);
    return 0;
}

Upvotes: 2

Views: 3490

Answers (2)

Treebeard
Treebeard

Reputation: 332

I've not compiled this so not sure how accurate it is, but I'd be working towards something like this in a modern compiler (pre C++17 still):

#include <functional>

class A {
  public:
    A(std::function<void(int)> func)
        : func_( func )
    {}
    
    std::function<void(int)> func_;
}

class B {
  public:
    void printer(int val) { /* do something */ }
}

int main()
{
    B b{};
    A a([&](int val) { b.printer( val ); });

    a.func_(1);

    return 0;
}

Upvotes: 5

Rabbid76
Rabbid76

Reputation: 210909

Pointers to function and pointers to member functions are different things. You need an object to call a member function.

A pointer to a meber function can be declared like this:

void (ClassB::*ptrPtrintFunc)(int) = &ClassB::printFun;

And you can call it like this:

ClassB classB;
(classB.*ptrPtrintFunc)(1);

or this:

ClassB *ptrClassB = &classB;
(ptrClassB->*ptrPtrintFunc)(2);

What you can do ist to use std::function instead a of the old school function pointer. You can pass a lambda function to the std::function, in which you call the method of the class:

#include <iostream>
#include <functional>   // std::function

struct ClassA
{
    using TFunc = std::function<void( int )>; // <-- std::function<void( int )> insted of void(*)(int)
    ClassA( TFunc func) : funPtr( func ) {}
    TFunc funPtr;
};

struct ClassB
{
    void printFun( int a ) { std::cout << a << std::endl; }
};

int main()
{
    ClassB classB;
    ClassA classA( [&classB]( int a ) { classB.printFun(a); } ); // <-- lambda function
    classA.funPtr(5);
    return 0;
}

Instead of the lambda function, you can also use std::bind with a std::placholder for the parameter:

ClassB classB;
ClassA classA( std::bind( &ClassB::printFun, &classB, std::placeholders::_1 ) );
classA.funPtr(5);

Of course you can also pass a simple function to std::function

void printFunc( int a ) { std::cout << a << std::endl; }

ClassA classA( printFunc ); 

Extension to the answer : Solution without using STL

Thanks for the information. I am using std library to print in the experimenting code. But the actual code I am writing is in kernel mode, so I will not have access to std library. I wonder if there is another way to do this.

If you don't want to use STL anyway you can think about a solution with an abstract base class. You need a base class with an abstract callback method and you need 2 derived classes which overrides the abstract callback method. The implementations of the callback methods delegate the callback either to a function or to class method.

Abstract class with the abstract methode CallBack:

struct CCallBack
{
    virtual void CallBack( int ) = 0;
};

Implementation for a function pointer. The overridden method CallBack delegates the callback to a function pointer:

struct CCallBackFunc : public CCallBack
{
    typedef void(*TFuncPtr)(int);
    TFuncPtr _funcPtr;
    CCallBackFunc( TFuncPtr funcPtr ) : _funcPtr( funcPtr ) {}
    virtual void CallBack( int a ) override { (*_funcPtr)( a ); }
};

Implementation for a method function pointer. The overridden method CallBack delegates the callback to an object and a method function pointer:

template < class T >
struct CCallBackMethod : public CCallBack
{
    typedef void(T::*TMethodPtr)(int);
    T &_obj;
    TMethodPtr _methodPtr;
    CCallBackMethod( T &obj, TMethodPtr methodePtr ) : _obj( obj ), _methodPtr( methodePtr ) {}
    virtual void CallBack( int a ) override { (_obj.*_methodPtr)( a ); }
};

Example for the use of both cases:

struct ClassA
{
    ClassA( CCallBack *cb ) : _cb( cb ) {}
    virtual ~ClassA() { delete _cb; }
    CCallBack *_cb;
};

struct ClassB { void printFun( int a ) { std::cout << a << std::endl; } };
void printFun( int a ) { std::cout << a << std::endl; }

int main()
{
    ClassB classB;
    ClassA classA0( new CCallBackFunc( &printFun ) );
    ClassA classA1( new CCallBackMethod<ClassB>( classB, &ClassB::printFun ) );
    classA0._cb->CallBack( 6 );
    classA1._cb->CallBack( 7 );
    return 0;
}

Upvotes: 7

Related Questions