Function pointers

Hi,

this piece of code compiles fine
1
2
3
4
5
6
7
8
 double Multiply(void) {return 1.0;} ;
 double (*GetFPointer(void))(void) {
    return &Multiply;
 }

int main(){
  return 0;
}


but if I try to include these functions in a class like this:
1
2
3
4
5
6
7
8
9
10
class T{
double Multiply(void) {return 1.0;} ;
double (*GetFPointer(void))(void) {
  return &Multiply;
  }
};

int main(){
  return 0;
}


I get the following compilation error:
1
2
3
check.cc: In member function ‘double (* T::GetFPointer())()’:
check.cc:4: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say ‘&T::Multiply’
check.cc:4: error: cannot convert ‘double (T::*)()’ to ‘double (*)()’ in return


What am I doing wrong?

Last edited on
Function pointers to class methods have an implied this parameter, making them different from a normal function. You need to change you function pointer to reflect that.
The error message basically says all.
You cannot call a non-static member function without an object.
In this case, it would make sense to make the functions static or rather to put them into a namespace instead of a class.
pointers to member functions have a quite awful syntax:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class T
{
    public:
        double Multiply(void) {return 1.0;}
        typedef double (T::*fptr)(void); // typedef for better readability 
        fptr GetFPointer(void)
        {
            return &T::Multiply;
        }
};

int main()
{
    T t;
    T::fptr p;
    p = t.GetFPointer(); // get function pointer
    (t.*p)(); // call function pointer
  return 0;
}
Last edited on
Thanks Bazzy.. That solved the problem.
I have a follow up question. The following code is broken. But is it possible to set up something like this?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;
class T{
public:
  double Multiply(double var) {return var*2.0;} ;
  double Divide(double var) {return var/2.0;} ; 
  typedef double (T::*fptr)(double);

  fptr GetFpointer(bool arg){
    if (arg) return &T::Multiply;
    else return &T::Divide;
  }
   // code which sets a function called Operation 
   set_function(bool mult){
  if(mult) {/*Operation is set to  multiply*/};
  else {/*Operation is set to divide*/};
 }


};


int main(){

//something like this will be nice
T t;
t.set_function(1);
cout<< t.Operation(40)<<endl;
  return 0;
}
Last edited on
jhapk wrote:
But is it possible to set up something like this?

Sure!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
using namespace std;
class T
{
public:

    enum OPCODE {ADD=0,SUB=1,MUL=2,DIV=3};

    void SetOperation(OPCODE op_code)
    {
        cur_op=op_table[op_code];
    }

    double DoOperation(double var)
    {
        return (this->*cur_op)(var);
    }

private:

    double Add(double var) {return var+5.0;}
    double Sub(double var) {return var-5.0;}
    double Mul(double var) {return var*2.0;}
    double Div(double var) {return var/2.0;}

    typedef double (T::*fptr)(double);

    static const fptr op_table[4];
    fptr cur_op;
};

const T::fptr T::op_table[]=
{
    &T::Add,&T::Sub,&T::Mul,&T::Div
};

int main()
{
    T t;

    t.SetOperation(T::ADD);
    cout << t.DoOperation(50) << endl;

    t.SetOperation(T::SUB);
    cout << t.DoOperation(50) << endl;

    t.SetOperation(T::MUL);
    cout << t.DoOperation(50) << endl;

    t.SetOperation(T::DIV);
    cout << t.DoOperation(50) << endl;

    cout << "\nhit enter to quit";
    cin.get();
    return 0;
}
Last edited on
Hi,

thank you so much for that reply. It works really well. Can you please explain though, whats happening in the following line:
1
2
3
4
const T::fptr T::op_table[]=
{
    &T::Add,&T::Sub,&T::Mul,&T::Div
};

I am not able to understand it.
It's creating an array of function pointers, with the first element being a pointer to Add(), and so on.
Hi,

I am trying to implement the above code by m4ster r0shi in a group code for a particular class "Class_Name". Inside my class declaration I have these statements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Class Class_Name{
public:
 //other stuff

   typedef void (Class_Name::*fptr)(const int B);

   static const fptr set_wall[2];
   fptr apply_wall;

   void apply_wall(const int B){
     (this->*apply_wall)(B);
   }

 void set_function(const int  A){                                                                                           
     bool C = !A;                                                                        
     apply_wall=set_wall[C];                                                                    
   }  

  void wall (const int B);
  void no_wall(const int B);
};

And outside the class declaration, I have these lines
1
2
3
4
5
6
7
8
9
10
11
12
13

void Class_Name::wall(const int B){
/* description of wall function */
}

void Class_Name::no_wall(const int B){
/* description of no_wall function */
}
const Clas_Name::fptr Class_Name::set_wall[]=
  {
    &Class_Name::no_wall,
    &Class_Name::wall
  };


I use a makefile to compile this group code. And all the individual files compile fine, but while linking the files I get the following error message at the very end of the compiling process
1
2
'Filename.o:(.rodata+0x72c): multiple definition of `Class_Name::set_wall'
Filename.o:(.rodata+0x10): first defined here


Any clues?
Last edited on
Ah, you probably have this:

1
2
3
4
5
const Clas_Name::fptr Class_Name::set_wall[]=
{
    &Class_Name::no_wall,
    &Class_Name::wall
};

inside a header file that you include more than one times in your code. Try removing it from here (from the header) and putting it in a separate cpp file (in which you will also include your header of course).
Last edited on
you were right m4ster r0shi. Thanks a lot.
Is it possible to make the SetOperation function in the original code by "m4ster r0shi" static? I am getting compile time errors with that. Anything logically wrong with that?
Basically, I just want to "SetOperation()" once in the very beginning of the run depending on some input parameters and not touch it again. Is it possible to do it without actually initializing an object of the class?
You can make SetOperation static but then you also have to make cur_op static, as static functions can't operate on non-static members.

EDIT:

jhapk wrote:
Is it possible to do it without actually initializing an object of the class?

Don't use a class at all. And if you really want to wrap your functions use a namespace instead.

http://www.cplusplus.com/doc/tutorial/namespaces/

EDIT 2: Oh, I guess you want to protect the private members... Then stick with the class but make all members static.
Last edited on
Ok, this is what it should look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
using namespace std;

class T
{
public:

    enum OPCODE {ADD=0,SUB=1,MUL=2,DIV=3};

    static void SetOperation(OPCODE op_code)
    {
        cur_op=op_table[op_code];
    }

    static double DoOperation(double var)
    {
        return (*cur_op)(var);
    }

private:

    static double Add(double var) {return var+5.0;}
    static double Sub(double var) {return var-5.0;}
    static double Mul(double var) {return var*2.0;}
    static double Div(double var) {return var/2.0;}

    typedef double (*fptr)(double);

    static const fptr op_table[4];
    static fptr cur_op;
};

const T::fptr T::op_table[]=
{
    &T::Add,&T::Sub,&T::Mul,&T::Div
};

T::fptr T::cur_op;

int main()
{

    T::SetOperation(T::ADD);
    cout << T::DoOperation(50) << endl;

    T::SetOperation(T::SUB);
    cout << T::DoOperation(50) << endl;

    T::SetOperation(T::MUL);
    cout << T::DoOperation(50) << endl;

    T::SetOperation(T::DIV);
    cout << T::DoOperation(50) << endl;

    cout << "\nhit enter to quit";
    cin.get();
    return 0;
}

thanks m4ster r0shi. this is exactly I wanted.
Topic archived. No new replies allowed.