我有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");
}
答案 0 :(得分:13)
类的静态成员函数最终与常规函数没有区别。他们真的只是语法糖;该函数的名称只包含Classname::
。
非静态成员完全是另一回事。关于非静态成员函数(NSMF),有两件重要的事情需要记住。
首先,每个非静态成员函数都可以访问它们所属的类的非静态成员。即使您可以有两个同一类的对象碰巧存储不同的数据,这也是可能的。如果您有两个std::string
个对象,它们每个都存储不同的字符串。在一个字符串上执行find
可以在一个字符串中返回找到的结果,而不是另一个字符串。
这是因为每个NSMF都有一个隐式this
指针。 this
不仅指一个类,而且还指NSMF运行的实际对象。当你这样做时:
std::string aString("data");
aString.find("da");
find
函数接受一个字符串参数,但它也aString
为this
。每次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的成员符合上述ReturnType
和ParameterList
,那么您可以填写arg
,如下所示:
arg = &ClassName::Function;
规则#3:非静态成员指针不是指针。是的,它们可以设置为NULL(技术上,它们可以设置为0),但它们不与指针相同。
大多数真正的C和C ++编译器都允许您将函数指针强制转换为void*
并返回。标准考虑了这种未定义的行为,但这并不是完全未知的。在几乎所有的C ++编译器中,你绝对不能使用NSMF指针执行此操作。实际上,sizeof(MemberPointerType)
可能与void*
的大小不同。
因此,NSMF指针不是常规指针。不要这样对待它们。
答案 1 :(得分:2)
在C ++ 11中,他们提出了一种方法。阅读function和bind操作。
在你的情况下,假设你想调用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;
}
};