简体   繁体   中英

Can I pass a member function pointer from within a constructor?

Knowing how things roll around here somebody is gonna mark this "dupe" right away I'm sure but I sure can't find a good example for "passing member function from constructor". Plenty of passing TO constructors or passing member functions outside, but not from inside a constructor...

Story: We are using a library that uses 'mailboxes', and provides a hook for RX interrupt callbacks. We have our own class for devices. Each object-instance needs to be able to handle one of the libraries mailboxes. Therefore constructor takes a mailbox (maybe > 1 in future), and then registers itself with the comms library.

Simply: I want each objects constructor to pass a pointer to its "Handler" member function to this library.

The problem is of course with member functions vs. standard function pointers. Standard function pointer works fine, a static class function 'works' but we need to work with local object variables not static class variables.

I have read a million threads on this and see the problems between member functions with hidden 'this' arguments vs standard C function pointers etc. etc.

Have attempted to use lambda and std::function<> approaches... Maybe I am fighting the impossible? Is it impossible to pass a pointer to a function before the constructor completes creating the instance?

Example... (there is also a Class hierarchy for code-reuse purposes and there will be some function overrides and extensions in subclasses, but the basic mailbox setup should be in the top base class)


class Base // Object that processes received communication frames
{
public: 
    Base(int);
    bool Initialized;
protected:
    fooframestruct rxframe;
    bool newframe;
    void Handler(const fooframestruct&);
    void DoOtherStuff();
};

Base::Base(int rxmailbox) : 
    Initialized(false),
    newframe(false)
{
    // point comms library to instance function when data received by its mailbox
    somelibraryobject.OnReceive(rxmailbox, this->Handler);  // obviously doesn't work cuz member func
}

void Base::Handler(const fooframestruct &thisframe)
{
    // callback function - just grab the frame and set a flag
    rxframe = thisframe;
    newframe = true;
}

void Base::DoOtherStuff()
{
    cout << "blah";
    Initialized = true;
}

class SubClass : Base
{
public:
    using Base:Base;
    void ExtendWithOtherStuff();
}   


main 
{

Base device1 = new Base(1);
Base device2 = new Base(7);
SubClass device3 = new Base(5);

// etc. 

}

Naturally compiler failure, invalid use of non-static member function, which as described above, I fully understand why, just not what the best way forwared is.

I realize I could do things like create a secondary class function say

Base.RegisterMB() 

and then call that in the main setup such like:

Base device1 = new Base(1);
device1.RegisterMB();

But I hate the '2 step object init'. I suppose a 3rd workaround would be setting the library up outside the Class aka...

somelibraryobject.OnReceive(rxmailbox, device1.Handler); 

or at least something like that , but again, I'd rather encapsulate the object setup if possible.

But maybe I can't?

Member functions require instance of object to be invoked. While standard components offer ways to do so, none lead to production of function pointer.

In this particular case you can return address only to a static or global function, or captureless lambda.If you have to "capture" state of your object, you have devise such mechanism yourself. Eg you may have factory\\pool\\manager which can allow to query existing object based on some parameter, passing pointer in parameters (visitor pattern?) and such.

The answer to the question is: no.

  1. Create a static function that gets registered exactly once.
  2. Create a static list in your class that registers each instance in that list. Have it de-register each instance on that instance's destruction.
  3. When that static function gets called have it call each instance with the relevant function.

Worst case is you have no instances and the static function gets called and has nothing to do.

Can you make somelibraryobject.OnReceive() accept your callback routine as a std::function ?

If so, you can use a capturing lambda to capture this , like so:

somelibraryobject.OnReceive (rxmailbox, [this] mutable () { this->Handler (); });

Live demo

If Handler() is declared const , then you don't need the mutable .

Basically answer is: NO can't do it inside a constructor , and, woefully C++-fighting-with-C painful to do it outside the constructor, resulting in just ugly bloated unreadable stupid code.

Outside of the constructor, in the main object setup, I also tried the std::bind approach outlined here: https://embeddedartistry.com/blog/2017/1/26/c11-improving-your-callback-game

Client c;
register_callback(std::bind(&Client::func, &c, std::placeholders::_1));

(I should point out - same as suggested by Zaiborg from the start) But no love there either. no instance of overloaded function matches argument list.

More pain than value here... I'm going to just abandoned ability to use interrupt driven logic and have to clumsily poll for messages all the time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM