C++ 将类成员函数作为函数参数传递

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7218519/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:37:36  来源:igfitidea点击:

Pass a class member function as a function parameter

c++syntax

提问by user593747

I have 2 C++ Class questions:

我有 2 个 C++ 类问题:

The 1st question is: How can I make it so I can pass a class member function as a parameter in another function & how can I then run/call that function? And how can I do the same with a class static function. It maybe 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 2nd question is: Is it bad(or dangerous) practice to call a class member (or static) function indirectly like the above. I have a feeling this is really bad C++ practice?

第二个问题是:像上面那样间接调用类成员(或静态)函数是不好的(或危险的)做法。我有一种感觉,这是非常糟糕的 C++ 实践?

EDIT: Implementing adviceThanks for the reply, I have attempted to implement that advice, its alot to get my head around though, would this be correct?

编辑:实施建议感谢您的答复,我已经尝试实施该建议,但它让我大开眼界,这是否正确?

    // 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");
    }

回答by Nicol Bolas

Static member functions of classes are ultimately no different than regular functions. They're really just syntactic sugar; the function is simply has a name that include Classname::.

类的静态成员函数最终与常规函数没有区别。它们实际上只是语法糖;该函数只是有一个包含Classname::.

Non-static members are another matter altogether. There are two important things to remember about non-static member functions (NSMF).

非静态成员完全是另一回事。关于非静态成员函数 (NSMF),有两件重要的事情要记住。

First, every non-static member function has access to the non-static members of the class that they are a member of. This is possible even though you can have two objects of the same class that happen to store different data. If you have two std::stringobjects, they each store different strings. Executing a findon one string can return a found result in one but not the other.

首先,每个非静态成员函数都可以访问它们所属的类的非静态成员。即使您可以有两个碰巧存储不同数据的同一类的对象,这也是可能的。如果您有两个std::string对象,它们各自存储不同的字符串。find对一个字符串执行 a可以返回一个找到的结果,而不是另一个。

This is because every NSMF has an implicit thispointer. thisrefers to, not merely a class, but the actual objectupon which that NSMF operates. When you do this:

这是因为每个 NSMF 都有一个隐式this指针。this指的不仅仅是一个类,而是NSMF 操作的实际对象。当你这样做时:

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

The findfunction takes a string argument, but it also gets aStringas its this. Every time findlooks for the members of its class, it will be looking at aString's data.

find函数接受一个字符串参数,但它也aString作为它的this. 每次find查找其类的成员时,它都会查看aString的数据。

So let's look at your prospective call of an NSMF:

因此,让我们看看您对 NSMF 的预期调用:

((*)nMemberFunction())

Where is the object that it gets its thispointer from? Without an object, the NSMF could not access the non-static members of the object, since there is no object for it to find them in. This is not legal.

this从哪里获取指针的对象?没有对象,NSMF 就不能访问该对象的非静态成员,因为它没有对象可以找到它们。这是不合法的。

So, rule #1 about NSMFs: You mustcall them with an actual instance of the class that the NSMF is a member of (or a derived class thereof). You cannot just take an NSMF pointer and call it like a function pointer; you have to call it on a live object of that type.

因此,关于 NSMF 的规则 #1:您必须使用 NSMF 所属类(或其派生类)的实际实例来调用它们。你不能只是把一个 NSMF 指针当作函数指针来调用;您必须在该类型的活动对象上调用它。

Rule #2: the syntax for NSMF pointers is really ugly.

规则#2:NSMF 指针的语法真的很难看。

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

要定义一个命名arg为 NSMF 指针类型的变量(或参数),你可以这样做:

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

Where ReturnTypeis the return type of the function, ParameterListis the list of arguments taken by the function, and ClassNameis the name of the class to which the NSMF pointer belongs.

其中ReturnType是函数的返回类型,是函数ParameterList采用的参数列表,ClassName是 NSMF 指针所属的类的名称。

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

鉴于丑陋,通常最好将其包装在 typedef 中:

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

Thus creating the typedef MemberPointerType, which is a NSMF pointer.

因此创建了 typedef MemberPointerType,它是一个 NSMF 指针。

Given an object named object, which is of type ClassName, you would call the member pointer argas follows:

给定一个名为 的对象object,其类型为ClassName,您可以arg按如下方式调用成员指针:

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

Where Paramsare the arguments you wish to pass. If objectis a pointer to a ClassNameinstead of a reference or a value, then you use object->*arginstead.

Params您希望传递的参数在哪里。如果object是指向 aClassName而不是引用或值的指针,则使用object->*arg代替。

One more thing: you mustuse &to get the member pointer name. Unlike function pointers, NSMF pointers do not automatically convert to member pointers. You have to ask for them directly. So if ClassNamehas a member called Function that fit the above ReturnTypeand ParameterList, you would fill argas follows:

还有一件事:您必须使用&来获取成员指针名称。与函数指针不同,NSMF 指针不会自动转换为成员指针。你必须直接问他们。因此,如果ClassName有一个名为 Function 的成员符合上述ReturnTypeand ParameterList,您将按arg如下方式填写:

arg = &ClassName::Function;

Rule #3: non-static member pointers are not pointers. Yes, they can be set to NULL (technically, they can be set to 0), but they are notthe same thing as a pointer.

规则#3:非静态成员指针不是指针。是的,他们可以设置为NULL(在技术上,它们可以被设置为0),但它们不是一回事指针。

Most real C and C++ compilers will allow you to cast a function pointer to a void*and back. The standards consider this undefined behavior, but it's not-entirely-unknown to do this. You absolutely cannotdo this with a NSMF pointer, on virtually all C++ compilers. Indeed, the sizeof(MemberPointerType)will likely not be the same size as void*.

大多数真正的 C 和 C++ 编译器都允许您将函数指针强制转换为 avoid*并返回。标准考虑了这种未定义的行为,但这样做并非完全未知。在几乎所有的 C++ 编译器上,你绝对不能用 NSMF 指针做到这一点。实际上, 的sizeof(MemberPointerType)大小可能与void*.

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

因此,NSMF 指针不是常规指针。不要这样对待他们。

回答by healthycola

In C++ 11 they came up with a way to do that. Read about functionand bindoperations.

在 C++ 11 中,他们想出了一种方法来做到这一点。阅读函数绑定操作。

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

在您的情况下,假设您想调用 test1 类型的函数。(即形式 bool FunctionName()。

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

And call it like this:

并这样称呼它:

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