2011-08-28 214 views
6

我有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"); 
    } 
+1

我很惊讶,这不是已经回答也许其他人是累过,不希望查找第500次成员函数指针的语法。 –

+1

请参阅http:// stackoverflow。com/questions/2463112 /指向ac-class-member-function-as-a-global-functions-parameter的链接http://www.parashift.com/c++-faq-lite/pointers- to-members.html在声明/使用普通和静态成员函数指针时有注意的语法和注意事项。至于是否坏,我会说:可能不是在特定情况下(如测试或其他人),但作为编写代码的日常练习并不是一件好事,因为它很棘手,并且因为对于大多数您可以使用它们的任何东西都有更好的机制。 – shelleybutterfly

回答

13

类的静态成员函数最终没有不同于普通函数。他们真的只是语法糖;该功能只是有一个名称,其中包括Classname::

非静态成员完全是另一回事。关于非静态成员函数(NSMF)有两件重要的事情要记住。首先,每个非静态成员函数都可以访问它们所属的类的非静态成员。即使可以有两个同一类的对象存储不同的数据,这也是可能的。如果您有两个std::string对象,则它们每个都存储不同的字符串。对一个字符串执行find可以在一个字符串中返回找到的结果,但不会在另一个字符串中返回。

这是因为每个NSMF都有一个隐含的指针thisthis指的不仅仅是一个类,而是NSMF在其上运行的实际的对象。当你这样做:

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

find功能需要一个字符串参数,但它也得到aStringthis。每次find寻找其班级的成员,它会查看aString的数据。

因此,让我们看看你的NSMF的前瞻性电话:

((*)nMemberFunction()) 

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

因此,有关NSMF的规则#1:您必须使用NSMF所属的类的实际实例(或其派生类)调用它们。你不能只带一个NSMF指针,并把它称为函数指针;您必须在该类型的实时对象上调用它。

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

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

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有一个成员叫功能适合上述ReturnTypeParameterList,你将填补arg如下:

arg = &ClassName::Function; 

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

大多数真正的C和C++编译器将允许您将函数指针投射到void*之后。标准认为这种未定义的行为,但这并不完全未知。你绝对是不能用在NSMF指针上做这件事,几乎所有的C++编译器都这样做。的确,sizeof(MemberPointerType)的尺寸可能不会与void*的尺寸相同。

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

+0

难道你不得不说'(object。* arg)(Params);'因为运算符优先级? –

+0

@Kerrek SB:是的,'。*'的优先级低于函数调用的优先级。 –

+0

@Nicol Bolas:谢谢你的回复。我试图实现你所说的,这是对的吗? – user593747

2

在C++ 11中,他们想出了一个办法。阅读有关functionbind的操作。

就你而言,假设你想调用test1类型的函数。 (即形式布尔使用functionName()的

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

,并调用它是这样的:

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