将类成员函数作为函数参数传递
Pass a class member function as a function parameter
我有两个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("rn");
}
void catalogueStaticTest( tstring testName, bool DebuggingManager::nStaticFunction )
{
debugLog += _T("Status of ") + testName + _T(": ") + nStaticFunction + _T("rn");
}
类的静态成员函数最终与正则函数没有什么不同。它们实际上只是句法上的糖;函数只是具有包括CCD_ 1的名称。
非静态成员完全是另一回事。关于非静态成员函数(NSMF(,有两件重要的事情需要记住。
首先,每个非静态成员函数都可以访问它们所属类的非静态成员。即使同一类的两个对象碰巧存储了不同的数据,这也是可能的。如果您有两个std::string
对象,它们各自存储不同的字符串。对一个字符串执行find
可以在一个字符串中返回已找到的结果,但在另一个字符串上则不能返回。
这是因为每个NSFF都有一个隐含的this
指针。this
不仅指一个类,而且指NSMF操作的实际对象。当你这样做时:
std::string aString("data");
aString.find("da");
find
函数接受一个字符串参数,但它也将aString
作为其this
。每次find
查找其类的成员时,它都会查看Classname::
0的数据。
因此,让我们来看看您对NSMF:的预期调用
((*)nMemberFunction())
this
指针来自哪个对象?如果没有对象,NSMF就无法访问对象的非静态成员,因为它没有对象可以在其中找到它们。这是不合法的。
因此,关于NSMF的规则#1:必须使用NSMF所属类(或其派生类(的实际实例来调用它们。您不能只获取一个NSFF指针并像函数指针一样调用它;你必须在这种类型的活动对象上调用它。
规则#2:NSMF指针的语法非常难看。
要定义NSMF指针类型的名为arg
的变量(或自变量(,请执行以下操作:
ReturnType (ClassName::*arg)(ParameterList);
其中,ReturnType
是函数的返回类型,ParameterList
是函数采用的参数列表,ClassName
是NSFF指针所属类的名称。
考虑到丑陋,通常最好将其封装在typedef:中
typedef ReturnType (ClassName::*MemberPointerType)(ParameterList);
从而创建typedef MemberPointerType
,它是一个NSMF指针。
给定一个名为object
、类型为ClassName
的对象,您将调用成员指针arg
,如下所示:
ReturnType value = (object.*arg)(Params);
其中Params
是要传递的参数。如果object
是指向ClassName
的指针,而不是引用或值,则使用object->*arg
。
还有一件事:必须使用&
来获取成员指针名称。与函数指针不同,NSFF指针不会自动转换为成员指针。你必须直接要求他们。因此,如果ClassName
有一个名为Function的成员,它符合上述ReturnType
和ParameterList
,那么您将按如下方式填充arg
:
arg = &ClassName::Function;
规则#3:非静态成员指针是而不是指针。是的,它们可以被设置为NULL(从技术上讲,它们可以设置为0(,但它们是而不是与指针相同。
大多数真正的C和C++编译器都允许您将函数指针投射到void*
并返回。标准考虑了这种未定义的行为,但这样做并非完全未知。在几乎所有的C++编译器上,使用NSMF指针是绝对不能做到这一点的。实际上,sizeof(MemberPointerType)
的大小可能与void*
的大小不同。
因此,NSMF指针不是常规指针。不要这样对待他们。
在C++11中,他们想出了一种方法来做到这一点。阅读有关函数和绑定操作的信息。
在您的情况下,假设您想要调用类型为test1的函数。(即形式为bool 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));
这是您想要的,其中X是您的类,T是您的方法的返回,Args是您的函数接收的参数。
如果您的方法不接受args,请不要像test1和test2那样传递它们。
如果您的方法有void返回,则擦除T模板并在方法签名上的T处写入void。
如果您有链接错误,请记住在.h文件中定义doMember和doStatic。我所说的define指的是编写整个函数,而不仅仅是它的签名。这是由于模板问题。
#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;
}
};
- 如何在C++中将迭代器作为函数参数传递
- 为什么我不能将引用作为 std::async 的函数参数传递
- 节点插件 API 将数组作为函数参数传递
- 将字符串数组作为函数参数传递
- 如何通过 C++ 中的函数参数传递初始值设定项列表的固定大小的初始值设定项列表?
- 我可以动态创建新地图并作为函数参数传递吗?
- 将任意模板向量作为函数参数C++传递
- 将函数指针作为函数参数传递的目的
- C++:通过函数参数传递的值给出不同的结果
- 当数组大小在C++中未知时,如何在运行时将对字符串数组的引用作为函数参数传递?
- 通过宏将函数参数传递给函数
- C++:访问作为函数参数传递的双指针数组所指向的变量的值
- 如何将 std::string 作为构造函数参数传递,并将其保存的 C 字符串存储在 void 指针中?
- 将派生类构造函数参数传递给受保护的成员
- 将指向数组的指针作为函数参数传递,这本身就是另一个函数的返回值?
- 如何将二维数组类型字符(字符串)作为函数参数传递?
- 有什么理由C++ 11+ std::mutex 应该声明为全局变量,而不是作为函数参数传递到 std::thread 中
- 如何将派生类作为函数参数传递:如果派生类成员不在父类中怎么办
- 如何将变量作为构造函数参数或函数参数传递
- 当数组对象以函数参数传递时,为什么复制构造函数会自称