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

时间:2011-08-28 01:34:10

标签: c++ syntax

我有2个C ++类问题:

第一个问题是:我怎样才能做到这一点,所以我可以将一个类成员函数作为参数传递给另一个函数&我怎么能运行/调用该函数?我怎么能用类静态函数做同样的事情。通过查看此代码可能更容易理解我的问题:

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() );
    }

};

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

编辑:实施建议 感谢您的回复,我试图实施这个建议,虽然它很多,但这是正确的吗?

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

3 个答案:

答案 0 :(得分:13)

类的静态成员函数最终与常规函数没有区别。他们真的只是语法糖;该函数的名称只包含Classname::

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

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

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

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

find函数接受一个字符串参数,但它也aStringthis。每次find查找其班级成员时,都会查看aString的数据。

那么让我们来看看你对NSMF的预期召唤:

((*)nMemberFunction())

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

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

规则#2:NSMF指针的语法非常难看。

要定义名为arg的NSMF指针类型的变量(或参数),请执行以下操作:

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

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

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

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

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

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

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

Params是您希望传递的参数。如果object是指向ClassName的指针而不是引用或值,那么您使用的是object->*arg

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

arg = &ClassName::Function;

规则#3:非静态成员指针不是指针。是的,它们可以设置为NULL(技术上,它们可以设置为0),但它们与指针相同。

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

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

答案 1 :(得分:2)

在C ++ 11中,他们提出了一种方法。阅读functionbind操作。

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

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

并称之为:

#wrapper {
    padding-left: 0;
    position: relative;
}

答案 2 :(得分:0)

这是您想要的,其中X是您的类,T是您的方法的返回,而Args是您的函数接收的参数。

如果您的方法不使用参数,则不要像在test1和test2中那样传递它们。

如果您的方法返回空值,则删除T模板并在方法签名上T所在的位置写空值。

如果遇到链接错误,请记住在.h文件中定义doMember和doStatic。通过定义,我的意思是编写整个功能,而不仅仅是其签名。那是由于模板问题。

#include <string>

class DebuggingManager
{

private:

    std::string testLog;

    bool test1()
    {
        // run test & return whether it passed or failed
        return true;
    }

    static bool test2()
    {
        return false;
    }

    int test3(int a, int b)
    {
        return a + b;
    }

    static int test4(int a, int b)
    {
        return a - b;
    }

    void catalogueTest(std::string testName, int result)
    {
        testLog += "Status of " + testName + ": " + std::to_string(result) + "\n";
    }

    // How can I call a member function?
    template <typename X, typename T, typename ...Args>
    T doMember(X* obj, T(X::* func)(Args...), Args... args)
    {
        return (obj->*func)(args...);
    }

    // How can I call a static function?
    template <typename T, typename ...Args>
    T doStatic(T func(Args...), Args... args)
    {
        return func(args...);
    }

public:

    // how do I pass a member function or a static function as a parameter in another function 
    void runTests()
    {
        catalogueTest("Test of member functin", doMember(this, &DebuggingManager::test1));
        catalogueTest("Test of member functin", doMember(this, &DebuggingManager::test3, 10, 20));
        catalogueTest("Test of static functin", doStatic(DebuggingManager::test2));
        catalogueTest("Test of static functin", doStatic(DebuggingManager::test4, 10, 20));
        std::cout << testLog << std::endl;
    }

};