Passing a member function to a function as a function parameter

I have questions about the C ++ class:

First question: how can I do this to pass a member function of a class as a parameter in another function and how can I run / call this function? And how can I do the same with a static class function. It might be easier to understand my question by looking at this code:

class DebuggingManager { string testLog; bool test1() { // run test & return whether it passed or failed } static bool test2() { } // How can I call a member function? void catalogueTest( string testName, bool DebuggingManager::*nMemberFunction ) { testLog += "Status of " + testName + ": " + ((*)nMemberFunction()) + "\n"; } // How can I call a static function? void catalogueTest( string testName, bool DebuggingManager::*nStaticFunction ) { testLog += "Status of " + testName + ": " + DebuggingManager::nStaticFunction() + "\n"; } // how do I pass a member function or a static function as a parameter in another function bool runTests() { catalogueTest( "Test of member functin", test1() ); catalogueTest( "Test of static functin", test2() ); } }; 

The second question: it is a wrong (or dangerous) practice to call a class function (or static) indirectly similar to the above. Do I feel like this is really bad practice in C ++?

EDIT: Implementation Tips Thanks for the answer, I tried to implement this advice, there is a lot of it to think about, will it be right?

  // I have a feeling that ParameterList is incorect, would I pass the implicit obj as a parameter or is it done automatically like in normal object function calls? typedef bool (DebuggingManager::*MemberPointerType)(ParameterList); void catalogueTest( tstring testName, DebuggingManager* obj, MemberPointerType *nMemberFunction ) { debugLog += _T("Status of ") + testName + _T(": ") + (obj->*nMemberFunction)() + _T("\r\n"); } void catalogueStaticTest( tstring testName, bool DebuggingManager::nStaticFunction ) { debugLog += _T("Status of ") + testName + _T(": ") + nStaticFunction + _T("\r\n"); } 
+7
source share
2 answers

Static member functions of classes are ultimately no different from ordinary functions. They are really just syntactic sugar; the function just has a name that includes Classname:: .

Non-static members are another matter entirely. There are two important things to keep in mind about non-static member functions (NSMFs).

First, each non-static member function has access to non-stationary members of the class of which they are a member. This is possible even if you can have two objects of the same class that store different data. If you have two std::string objects, each of them stores different strings. Running a find on one line can return the result found to one, but not the other.

This is because every NSMF has an implicit this pointer. this applies not only to the class, but also to the actual object that NSMF works with. When you do this:

 std::string aString("data"); aString.find("da"); 

The find function accepts a string argument, but also receives aString like this . Each time find searches for members of its class, it will search for aString data.

So let's look at your intended NSMF call:

 ((*)nMemberFunction()) 

Where is the object from which it gets its this pointer? Without an object, NSMF could not access the non-stationary members of the object, since there is no object to search for it. This is not legal.

So, rule # 1 on NSMF: you must call them with the actual instance of the class of which the NSMF is a member (or its derived class). You cannot just take the NSMF pointer and name it as a function pointer; you must call it on a living object of this type.

Rule # 2: NSMF pointer syntax is really ugly.

To define a variable (or argument) named arg type of the NSMF pointer, you do this:

 ReturnType (ClassName::*arg)(ParameterList); 

Where ReturnType is the return type of the function, ParameterList is the list of arguments that the function executes, and ClassName is the name of the class to which the NSMF pointer belongs.

Given the ugliness, it is usually best to wrap it in a typedef:

 typedef ReturnType (ClassName::*MemberPointerType)(ParameterList); 

This creates a typedef MemberPointerType , which is an NSMF pointer.

For an object named object that is of type ClassName , you call the arg member pointer as follows:

 ReturnType value = (object.*arg)(Params); 

Where Params are the arguments you want to pass. If object is a pointer to a ClassName instead of a reference or value, you use object->*arg instead.

One more thing: you must use & to get the name of the member pointer. Unlike function pointers, NSMF pointers are not automatically converted to member pointers. You must ask them directly. Therefore, if the ClassName has a member called Function that matches the above ReturnType and ParameterList , you populate arg as follows:

 arg = &ClassName::Function; 

Rule 3: non-static element pointers are not pointers . Yes, they can be set to NULL (technically they can be set to 0), but this is not the same as a pointer.

Most real C and C ++ compilers allow you to point to void* and vice versa. Standards consider this behavior undefined, but it is not entirely unknown for this. You absolutely cannot do this with the NSMF pointer on almost all C ++ compilers. Indeed, sizeof(MemberPointerType) will probably not be the same size as void* .

So, NSMF pointers are not regular pointers. Do not treat them as such.

+13
source

In C ++ 11, they came up with a way to do this. Read about function and bind operations.

In your case, let's say you wanted to call functions like test1. (i.e. forms bool FunctionName ().

 void catalogueTest( string testName, std::function<bool()> myFunction) { testLog += "Status of " + testName + ": " + myFunction() + "\n"; } 

And name it as follows:

 DebuggingManager myInstance myInstance->catalogueTest("TestName", std::bind(&DebuggingManager::test1, myInstance)); 
+2
source

All Articles