8

I have a class A which contains member functions foo() and bar() which both return a pointer to class B. How can I declare an array containing the functions foo and bar as a member variable in class A? And how do I call the functions through the array?

3 Answers 3

21

The member function pointer syntax is ReturnType (Class::*)(ParameterTypes...), so e.g.:

typedef B* (A::*MemFuncPtr)(); // readability
MemFuncPtr mfs[] = { &A::foo, &A::bar }; // declaring and initializing the array
B* bptr1 = (pointerToA->*mfs[0])(); // call A::foo() through pointer to A
B* bptr2 = (instanceOfA.*mfs[0])(); // call A::foo() through instance of A

See e.g. this InformIT article for more details on pointers to members.

You might also want to look into Boost.Bind and Boost.Function (or their TR1 equivalents) which allow you to opaquely bind the member-function-pointers to an instance:

typedef boost::function<B* ()> BoundMemFunc;
A instanceOfA;
BoundMemFunc mfs[] = { 
    boost::bind(&A::foo, &instanceOfA), 
    boost::bind(&A::bar, &instanceOfA) 
};
B* bptr = mfs[0](); // call A::foo() on instanceOfA

To use such an array as a member, note that you can't initialize arrays using the member initializer list. Thus you can either assign to it in the constructor body:

A::A {
    mfs[0] = &A::foo;
}

... or you use a type that can actually be initialized there like std::vector or boost::array:

struct A {
    const std::vector<MemFuncPtr> mfs;
    // ...
};

namespace {
    std::vector<MemFuncPtr> init_mfs() {
        std::vector<MemFuncPtr> mfs;
        mfs.push_back(&A::foo);
        mfs.push_back(&A::bar);
        return mfs;
    }
}

A::A() : mfs(init_mfs()) {}
Sign up to request clarification or add additional context in comments.

2 Comments

@DeadMG: I mentioned the TR1 version but went for the Boost version as it has the broadest availability. I personally consider the C++0x versions as not widespread enough and the new standard is also not finalized yet.
Ah, so you did. Since I got a C++0x compiler myself, I'm not used to seeing the boost variants.
2

What you're looking for are pointers to member functions. Here is a short sample that shows their declaration and use:

#include <iostream>

class B {
public:
  B(int foo): foo_(foo) {
    std::cout << "Making a B with foo_ = " << foo_ << std::endl;
  }
  ~B(void) {
    std::cout << "Deleting a B with foo_ = " << foo_ << std::endl;
  }
  int foo_;
};

class A {
public:
  A(void) {
    funcs_[0] = &A::foo;
    funcs_[1] = &A::bar;
  }

  B* foo(void) {
    return new B(3);
  }

  B* bar(void) {
    return new B(5);
  }

  // Typedef for the member function pointer, for everyone's sanity.
  typedef B* (A::*BMemFun)(void);
  BMemFun funcs_[2];
};

int main(int argc, char *argv[]) {
  A a;
  for (int i = 0; i < 2; ++i) {
    A::BMemFun func = a.funcs_[i];
    // Call through the member function pointer (the .* operator).
    B* b = (a.*func)();
    delete b;
  }
  return 0;
}

The C++ FAQ section on pointers to member functions is where I found all this information.

Comments

0

C++ that's not ancient (read: C++11 and later) makes this all easier. In modern C++, you can do

#include <vector>
class B;
class A {
   public:
    B* foo() {
        // return something;
        return nullptr;
    }

    B* bar() {
        // return something;
        return nullptr;
    }
    
    //C++ 11: functional brings std::function, which has zero overhead 
    //but is actually a useful type with which one can work
    std::vector<std::function<B*()>> container;

    /* [=]() { return foo(); }
     * that's a lambda. In practice it "compiles away", i.e. calling
     * the lambda function is the same as calling foo or bar directly
     * Note how [=] means we're passing in "this", so that we can 
     * actually call foo().
     */
    A() : container{{[=]() { return foo(); }}, {[=]() { return bar(); }}} {}
};

(Try on godbolt compiler explorer)

Here's a more complete example showcasing what to do with these.


An architectural remark: Be careful with pointers to non-static member functions. What happens if your instance of A gets destroyed, but you still have a function handle to a member function? Right, hell freezes over: There's no object anymore to which this method belongs, so results are catastrophic.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.