Search code examples
c++function-pointerspointer-to-member

How to get a function pointer to a member function


I was working on a project where I needed to get involved with function pointers, more specifically function pointer to member functions. I have read almost all the related questions, however none of them describing my specific problem. So, I will try to describe my problem by a simple example.

Let's assume that I have three different header files with different classes, like given below:

foo1.h

struct Foo1{
    int a1;
    double b1;
    
    void (Foo2::*fp)(const double);
}

foo2.h

#include "foo1.h"

class Foo2{
public:
    void print_foo2(const double p){
        cout << "From Foo2: " << p << endl;
    }
    
    Foo1 foo1;
}

foo3.h

class Foo3 : public Foo2{
    Foo1 foo1;
    
    foo1.fp = &Foo2::print_foo2; // cannot do that
}

So, one of the member variables of struct Foo1 is a function pointer to the member function of Foo2, namely print_foo2. For that reason, I create instance of object foo1 and assign it a pointer to the print_foo2. Class Foo3 inherits from class Foo2.

I noted that, as I thought, may be it can be useful information for solution of the problem. However, I cannot get that pointer to the function as Foo2 is not recognized inside struct Foo1. Even including foo2.h in foo1.h doesn't help. If I am not mistaken, this is because Foo1 requires Foo2 for its member variable during construction, but in the same way Foo2 requires Foo1 to be constructed. So, this creates a deadlock.

Is it the cause of the problem? If yes, how can I solve it?


Solution

  • Since both Foo2 and Foo3 need the definition of Foo1, they should both #include "foo1.h". Without the definition of Foo1 the compiler will not be able to calculate the size of neither Foo2 nor Foo3.

    Foo1 on the other hand does not need the definition of Foo2 and can therefore forward declare Foo2 to resolve the deadlock. The pointer (fp) it keeps will have the same size no matter how Foo2 is defined which is why a forward declaration is enough.

    Comments inline:

    // foo1.h
    #pragma once
    
    class Foo2;       // forward declaration
    
    struct Foo1{
        int a1;
        double b1;
        
        void (Foo2::*fp)(const double);
    };
    
    // foo3.h
    #pragma once
    
    #include "foo2.h"
    #include "foo1.h" // not strictly needed since `foo2.h` includes it
    
    class Foo3 : public Foo2{
    
        // proper initalization:
    
        Foo1 foo1{1, 3.141, &Foo2::print_foo2};
    };
    

    Note: In your code, both Foo2 and Foo3 has a Foo1 member variable. That means that Foo3 has 2 in total. If you only one one Foo1 in Foo3 and instead want Foo3 to initialize the Foo1 in the inherited Foo2, you can remove the Foo1 member from Foo3 and initialize the base class (Foo2) like so:

    class Foo3 : public Foo2{
    public:
        Foo3() : Foo2{1, 3.141, &Foo2::print_foo2} {}
    };