4

I want add a logger function to a worker class, how to pass a member function as a function pointer? use mem_fun?

here is the code sample:

class Work{
public:
    void (*logger) (const string &s);
    void do_sth(){if (logger) logger("on log")};
};

classs P{
public:
    void log(const string &s)(cout << s);
};

int main(){
    Work w;
    P p;
    w.logger = &p.log;
    w.do_sth();
}

edit:

I don't want to use void (P::*xxx)() because it stick to class P...

I know C++ hide sth, the real log function is: void log(P &p, const string &s),

and the real project is like this:

I create a CDialog, and there is a log function, it copy the log string to a CEdit.

So I need pass this log function to a Worker class, this class do some serial port job,

I need log and show the data send and recived...

linjunhalida
  • 4,538
  • 6
  • 44
  • 64

3 Answers3

5

You can accomplish this using std::function and std::bind:

#include <functional>
#include <iostream>
#include <string>

class Work {
public:
    std::function<void(const std::string&)> logger;
    void do_sth() { logger("on log"); }
};

class P {
public:
    void log(const std::string& s) { std::cout << s; }
};

int main() {
    Work w;
    P p;
    w.logger = std::bind(&P::log, p, std::placeholders::_1);
    w.do_sth();
}

Note that function and bind may not be in your implementation's standard library yet; you can also get them from the Boost libraries.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • @James McNellis, shouldn't `std::placeholders::_1` be `std::tr1::placeholders::_1` instead? – Praetorian Aug 04 '10 at 03:01
  • In my real project, I use(and compiled OK): using namespace std; device.logger = boost::bind(&CDeviceTesterDlg::logger, this, _1); – linjunhalida Aug 04 '10 at 03:04
  • @Praetorian: It depends where you get `bind` from. Various older implementations have it and related names in namespace `std::tr1`, which was the place specified for them in the TR1 library extensions specification; the latest standard library releases have the names in namespace `std`, which is where they are specified to be located in (the forthcoming) C++0x standard. – James McNellis Aug 04 '10 at 03:04
  • @linjunhalida: For the sake of whomever might have to maintain your code, please, please, please don't use `using namespace std;`. There's no good reason to use it and it only causes trouble. – James McNellis Aug 04 '10 at 03:06
  • I take the suggestion, why don't use using namespace std? any discussion link? – linjunhalida Aug 04 '10 at 03:12
  • @linjunhalida: No, there is no good reason to use `using namespace anything;`. Just spell out the namespace name; it's much less effort to do that in the long run. As an off-the-top-of-my-head link, [I just answered another question](http://stackoverflow.com/questions/3401878/why-didnt-the-positive-terms-get-displayed-in-this-asbolute-program) about a problem caused (at least partially) by `using namespace std;`. As a general discussion question, see [Why is ‘using namespace std;’ considered a bad practice in C++?](http://stackoverflow.com/questions/1452721/) – James McNellis Aug 04 '10 at 03:22
  • @James McNellis, I agree that `using namespace foo` is bad within a header, especially if made at file level, since it imposes itself on every source file that includes that header. But what's wrong with using it within a source file? I disagree with the answer in that discussion you linked to. If a future upgrade causes a name conflict and the function parameters do not match, the compiler will consider it a case of overloading and call the right function. On the other hand, if parameters match you will get errors for ambiguous calls, in which case a simple search-replace fixes the issue. – Praetorian Aug 04 '10 at 06:36
1

The only way to do it is as a static function. Unfortunately a static function isn't tied to a single object, but is global to the class. If you're lucky, the function taking a function pointer will also take a void*, which you can use to tie back to the original object - your static function can cast that back to an object pointer and call another function on the object to do the actual work.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
0

This would require closures, that C++ doesn't exactly have. You can make functors and use templates, but you'll have to go somewhat out of your way.

zneak
  • 134,922
  • 42
  • 253
  • 328