john smith
john smith

Reputation: 649

Pointers to member functions in C++

This is actually for a chess playing program, but the code is too long to post here so I'm going to use a simpler unrelated example:

Let's say I have an object like this:

class A{
    int x1;
    int x2;
public:
    int Average(){ return (x1+x2)/2; }
};

I want to have a vector called AveragesList that stores all the averages (or a pointer to them) of all the x1 and x2 values of every object. So I tried doing this:

vector<int>* AveragesList;

class A{
    int x1;
    int x2;
public:
    int Average(){ return (x1+x2)/2; }
    A(){ AveragesList.push_back(this->Average); } //trying to add pointer to member function Average() to AveragesList
};

But when I try this, I get a message saying "A pointer to a bound function may only be used to call a function". Is there a work around? I don't want to simply put value of the average of x1 and x2 in AveragesList, because if x1 or x2 changes, the value in AveragesList will not. Also, my book said not to use public variables in C++ classes, so I'm not sure if I should use one.

Upvotes: 4

Views: 692

Answers (3)

paulsm4
paulsm4

Reputation: 121881

If you don't want to store the current value of "average" ... then why not store a reference to "A"?

EXAMPLE:

Class A{
    int x1;
    int x2;
public:
    A (int x1, int x2) { this->x1 = x1; this->x2 = x2; }
    int Average(){ return (x1+x2)/2 }
};

...

int
main (int argc, char *argv[])
{
  vector<A> averagesList;
  averagesList.push_back (new A(3, 4));
  ...

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727067

There is no built-in way of dealing with closures in C++ prior to C++11, so the easiest way of addressing the issue without using libraries such as boost would be as follows: define an integer member variable called average, in addition to your x1 and x2 variables. Set average to the right value when you create your object, and update it every time the x1 or x2 is changed. Store the pointer in the list, and use it to access the average.

This is not as good as calculating the result on the fly. If you are using C++11, a better solution is available:

#include <iostream>
#include <vector>
#include <functional>

class A{
    int x1;
    int x2;
public:
    A(int _x1, int _x2) : x1(_x1), x2(_x2) {}
    int Average(){ return (x1+x2)/2; }
    void setX1(int _x1) { x1 = _x1; }
    void setX2(int _x2) { x2 = _x2; }
};

using namespace std;

int main() {
    vector<std::function<int()>> v;
    A a1(1, 5);
    A a2(2, 8);
    v.push_back([&]{return a1.Average();});
    v.push_back([&]{return a2.Average();});
    for (int i = 0 ; i != v.size() ; i++) {
        cout << v[i]() << endl;
    }
    a1.setX1(7);
    a2.setX2(32);
    for (int i = 0 ; i != v.size() ; i++) {
        cout << v[i]() << endl;
    }
    return 0;
}

Upvotes: 4

user
user

Reputation: 7333

To do what (I'm guessing) you want to do, you also need to store the pointers of the objects that that you're going to use to call the functions:

#include <vector>
#include <iostream>

class A {
  int x1,x2;
public:
  int Average(){ return (x1+x2)/2; }
  A(int a, int b);
};

std::vector< A* > objectVec;
std::vector< int (A::*)() > functionPtrVec;

A::A(int a, int b):
  x1(a), x2(b) {
  objectVec.push_back(this);
  functionPtrVec.push_back(& A::Average);
}

int main() {
  A a1(1,3);
  A a2(10,20);

  for (int k=0; k<objectVec.size(); k++) {
    int (A::* memberFuncPtr)() = functionPtrVec[k];
    A*object = objectVec[k];
    std::cout << (object->*memberFuncPtr)() << std::endl;
  }
  return 0;
}

You could use a pair to store them in the same vector, or define your own member functor class that stores both the object, the member function pointer, and has an () operator.

HTH.

Upvotes: 1

Related Questions