Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting a pointer to a non-static member function

Tags:

c++

I'm trying to setup a function pointer that is set during execution based on a set of user parameters. I would like to have the function pointer point to a non-static member function but I can't find how to do it.

The examples I've seen say this can only be done with static member function only or use global variables in straight C.

A simplified example follows:

    class CA
    {
    public:
        CA(void) {};
        ~CA(void) {};
        void setA(double x) {a = x; };
        void setB(double x) {b = x; };

        double getA(const double x) {return x*a; };
        double getB(const double x) {return x*b; };

        void print(double f(const double), double x) {
            char cTemp[256];
            sprintf_s(cTemp, "Value = %f", f(x));
            std::cout << cTemp;
        };

    private:
        double a, b;
    };

The implementation part is

CA cA;
cA.setA(1.0);
cA.setB(2.0);

double (*p)(const double);

if(true) {
    p = &cA.getA;  //'&' : illegal operation on bound member function expression
} else {
    p = cA.getB;  //'CA::getB': function call missing argument list; use '&CA::getB' to create a pointer to member
                  //'=' : cannot convert from 'double (__thiscall CA::* )(const double)' to 'double (__cdecl *)(const double)'
}

cA.print(p, 3.0);

So how do I get p to point to either 'getA' or 'getB' so that it is still useable by 'print'.

From what I have seen, the suggestions are to use boost or std::bind but I've had no experience with either of these. I'm hoping that I don't need to dive into these and that I'm just missing something.

Compiler MSVC++ 2008

like image 476
Part Time User Avatar asked Feb 23 '13 01:02

Part Time User


People also ask

Which pointer is present inside every non-static member function?

The compiler supplies a special implicit pointer named this that allows a member function to access the non- static data members. The this pointer contains the address of the object that called the member function.

Can we create a pointer to a member function?

You can use pointers to member functions in the same manner as pointers to functions. You can compare pointers to member functions, assign values to them, and use them to call member functions.

Can we use this pointer in static member function?

The 'this' pointer is passed as a hidden argument to all nonstatic member function calls and is available as a local variable within the body of all nonstatic functions. 'this' pointer is not available in static member functions as static member functions can be called without any object (with class name).

How can one refer to a non-static member?

You either have to use a pointer to member, or a free function.


2 Answers

Don't forget that a member function accepts an implicit this parameter: therefore, a member function accepting a double can't be the same thing as a non-member (free) function accepting a double.

// OK for global functions
double (*p)(const double);

// OK for member functions
double (CA:*p)(const double);

Also the way you invoke them is different. First of all, with member functions, you need an object to invoke them on (its address will eventually be bound to the this pointer in the function call). Second, you need to use the .* operator (or the ->* operator if you are performing the call through a pointer):

p = &CA::getA;
CA cA;
(cA.*p)();

Consistently, you will have to change your definition of function print():

    #include <iostream>

    void print(double (CA::*f)(const double), double x) 
    {
        // Rather use the C++ I/O Library if you can...
        std::cout << "Value = " << (this->*f)(x);
    };

So finally, this is how you should rewrite your main() function:

int main()
{
    CA cA;
    cA.setA(1.0);
    cA.setB(2.0);

    double (CA::*p)(const double);

    if (true) // Maybe use some more exciting condition :-)
    {
        p = &CA::getA;
    } 
    else {
        p = &CA::getB;
    }

    cA.print(p, 3.0);
}
like image 113
Andy Prowl Avatar answered Sep 22 '22 18:09

Andy Prowl


Compilation Issue

This answer focuses on the compilation issue presented in the question. I would not recommend implementing this as a solution.

Pointers to member functions are best dealt with with typedefs and a macro.

Here's the macro for calling a member function:

#define CALL_MEMBER_FN(object, ptrToMember)  ((object).*(ptrToMember))

Source: [33.6] How can I avoid syntax errors when calling a member function using a pointer-to-member-function?, C++ FAQ.

This saves you having to remember the ugly (object).*(ptrToMember) syntax any time you wish to call a member function by pointer.

In your class, declare a typedef called CAGetter, this will make variable declaration much simpler:

class CA
{
public:    
    typedef double (CA::*CAGetter)(const double x);

Then you can declare your print() function quite simply:

    void print(CAGetter f, double x)

The body is also simple, clear and concise:

    {
        std::cout << "value = " << CALL_MEMBER_FN(*this, f)(x) << '\n';
    }

Sample usage:

CA a;
a.setA(3.1);
a.setB(4.2);

// Using a variable...
CA::CAGetter p = &CA::getA;
a.print(p, 1);

// without a variable
a.print(&CA::getB, 1);

// Calling the functions from outside the class...
std::cout << "From outside (A): " << CALL_MEMBER_FN(a, p)(10) << std::endl;
std::cout << "From outside (B): " << CALL_MEMBER_FN(a, &CA::getB)(10) << std::endl;

Design Issue

Passing a pointer to a member function into a method of an instance of the same class is a design smell (you wouldn't normally pass a member variable to a method, this is no different). There is not enough information in this question to address the underlying design issue but this problem could probably be solved with separate print() methods, a member variable or with inheritance and polymorphism.

like image 39
Johnsyweb Avatar answered Sep 24 '22 18:09

Johnsyweb