0

I am trying to create object of another class in one class (I am able to do this) and I want to pass a method of the first class to the second class as constructor argument (I am not able to do this. I get compiler errors). Below is the code.

#include <iostream>
using namespace std;
class B
{
    public:
        B(void (*fp)(void))
        {
            fp();
        }
    private: 
};

class A
{
    public:
    void printHelloWorld()
    {
        cout << "Hello World!" << endl;
    } 
    private:
    B ObjB{printHelloWorld};
};
     
int main()
{
    cout << "!!** Program Start **!!" << endl;
    
    A ObjA;
    
    cout << "!!** Program End **!!" << endl;
    return 0;
}  

I receive the following Errors.

main.cpp:21:27: error: could not convert ‘{((A*)this)->A::printHelloWorld}’ from ‘’ to ‘B’
   21 |     B ObjB{printHelloWorld};
      |                           ^
      |                           |
      |                           <brace-enclosed initializer list>

The code can be compiled on this link also https://onlinegdb.com/xB70hwQph

The code works fine if I make printHelloWorld as static function or Shift the defination of printHelloWorld outside the class.

I am looking for a solution for this simple looking problem.

  • Refer to [how to ask](https://stackoverflow.com/help/how-to-ask) where the first step is to *"search and then research"* and you'll find many related posts for this. You can try searching "how to pass member function in c++" etc – Jason Jan 27 '23 at 10:55

1 Answers1

0

You cannot use a non-static method as an argument for a C style function pointer parameter.
The reason is that in order to invoke it you need a this pointer which is not available with a C function pointer.

You can use std::function, together with a lambda capturing this to achieve what you need.

However - since you initialize your ObjB directly when it is declared, the complete A might not have been fully constructed yet (e.g. via a specific contructor) and therefore calling the method directly from B's constructor is problematic. In your trivial case it can work, but imagine the method printHelloWorld accessing some A members.
Instead I made B store the std::function so that it can later be invoked via the invokeF() method.

Code example:

#include <iostream>
#include <functional>

class B
{
public:
//----vvvvvvvvvvvvvvvvvvvvvvvvv----
    B(std::function<void(void)> fp) { m_fp = fp; }
    void invokeF() { m_fp(); }
private:
    std::function<void(void)> m_fp;
};

class A
{
public:
    void printHelloWorld() { std::cout << "Hello World!" << std::endl; }
    void invokeBF() { ObjB.invokeF(); }
private:
//----------vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv----
    B ObjB{ [this]() { printHelloWorld(); } };
};

int main()
{
    std::cout << "!!** Program Start **!!" << std::endl;
    A ObjA;
    ObjA.invokeBF();
    std::cout << "!!** Program End **!!" << std::endl;
    return 0;
}

Output:

!!** Program Start **!!
Hello World!
!!** Program End **!!

Demo (Godbolt)

A side note: Why is "using namespace std;" considered bad practice?.

wohlstad
  • 12,661
  • 10
  • 26
  • 39