C++ 将类成员函数作为参数从同一类的另一个成员函数中传递
我提供了一个我正在处理的问题的简单版本 我有一个类实体,它有一个用户对象的映射。为了简单起见,我只添加了一个elementname。我已经围绕userMap对象实现了getter和setter 包装器函数对于我来说是必需的,因为它可以处理多线程的情况。这里没有显示。我通过几个这样的线程实现了一个工作示例 但正如您所看到的,在过程函数中使用包装函数时,我必须在三个位置编写id、arg tuple参数。是否有一种方法可以实现相同的功能,方法是为函数参数设置某种占位符,以便调用包装器看起来很干净,即wrapper1、static_cast&name、function_ptrC++ 将类成员函数作为参数从同一类的另一个成员函数中传递,c++,c++11,c++14,C++,C++11,C++14,我提供了一个我正在处理的问题的简单版本 我有一个类实体,它有一个用户对象的映射。为了简单起见,我只添加了一个elementname。我已经围绕userMap对象实现了getter和setter 包装器函数对于我来说是必需的,因为它可以处理多线程的情况。这里没有显示。我通过几个这样的线程实现了一个工作示例 但正如您所看到的,在过程函数中使用包装函数时,我必须在三个位置编写id、arg tuple参数。是否有一种方法可以实现相同的功能,方法是为函数参数设置某种占位符,以便调用包装器看起来很干净,即w
谢谢 在我看来,我认为你强迫使用lambda是在给自己制造麻烦,我知道它们很有趣,但通常不是很有用。一般来说,保持简单的愚蠢之吻,在你的情况下,只需将函数分为两个单独的函数
class Entity {
public:
...
void getUserName(int id,void * arg);
void setUserName(int id,void * arg);
void procedure();
void criticalTask(int id); // critical task, based on id
};
void Entity::getUserName(int id,void *arg) {...}
void Entity::setUserName(int id,void *arg) {...}
void Entity::criticalTask(int id) {
cout <<"\nSome Other critical task based on id"<< endl;
}
void Entity::procedure() {
cout <<"Procedure starts"<<endl;
...
criticalTask(id);
getUserName(id, &name);
...
}
int main() {
Entity E;
E.procedure();
}
我将从一个直接的答案开始,但请继续阅读下面的警告 对于您尝试执行的操作,更简单的语法是将第三个参数的类型更改为wrapper。与其将成员函数转换为非成员函数,不如将成员函数作为参数
void wrapper(int id, void* arg, void (Entity::* func)(int,void*))
{
cout <<"\nSome Other critical task based on id"<< endl;
(this->*func)(id, arg);
}
这样您的通话就会变得更简单:
wrapper(1, static_cast<void*>(&name), &Entity::getUserName);
wrapper(1, static_cast<void*>(&name), &Entity::setUserName);
然而,这真的是你想要采取的方法吗?您依赖于人们记住调用包装器,而不是直接调用其他成员函数。如果你在某个时候忘记使用包装器,你能根据症状找出原因吗?你想试试吗
一种更健壮的方法是将关键任务放在它自己的函数中,然后让getter和setter调用它。更像是:
void criticalStuff(int id)
{
cout <<"Some critical task based on id\n";
}
void Entity::getUserName(int id, string & arg)
{
criticalStuff(id); // Critical stuff first.
auto iter = userMap.find(id);
if(iter != userMap.end()) {
arg = iter->second.name;
}
}
void Entity::setUserName(int id, const string & arg)
{
criticalStuff(id); // Critical stuff first.
auto iter = userMap.find(id);
if(iter != userMap.end()) {
iter->second.name = arg;
}
}
任何添加新字段的人在编写新的getter和setter时都必须记住关键内容,但更常见的情况是调用这些函数会自动处理关键内容。此外,您还可以恢复参数的类型检查,因为似乎不再有理由将内容强制转换为void*不是,例如wrapper1、static_cast&name、getUserName;通过隐式转换完成工作。只是一个未经检验的想法@科尔尼。它显示,无效使用非静态成员函数“void Entity::getUserNameint,void*”错误。它不适用于类成员函数。请考虑只使用类成员函数。@ DeBasHISH更新了我的答案-> GETUsReNEX是一个无效的非静态成员函数名称的使用。形成指向成员的指针的唯一方法是使用&Entity::getUserName语法。@aschepler您说得对,谢谢,刚刚删除了此部分。避免函数指针和lambdas也是更好的解决方案。define CALL_MEMBER_FNobject,ptrtomber object.*ptrtomber void Entity::wrapperint id,void*arg,void Entity::*funcint,void*{cout
wrapper(1, static_cast<void*>(&name), &Entity::getUserName);
wrapper(1, static_cast<void*>(&name), &Entity::setUserName);
void criticalStuff(int id)
{
cout <<"Some critical task based on id\n";
}
void Entity::getUserName(int id, string & arg)
{
criticalStuff(id); // Critical stuff first.
auto iter = userMap.find(id);
if(iter != userMap.end()) {
arg = iter->second.name;
}
}
void Entity::setUserName(int id, const string & arg)
{
criticalStuff(id); // Critical stuff first.
auto iter = userMap.find(id);
if(iter != userMap.end()) {
iter->second.name = arg;
}
}