如何使用指向成员函数的指针进行切换?
好吧,我想要做的只是一个带有函数指针的“开关”,但带有方法指针。开关是,如果我调用方法Run(),它将重定向到A::RunOn()或A::RunOff()根据Runptr 指向这些成员函数。
我知道这是可以做到的。我是用普通的c 语言完成的,但我已经搜索并用 google 搜索了在c++ 中做同样的事情,但没有运气。
class A
{
typedef (void)(A::*RunPtr)(int);
RunPtr RunMethod;
public:
RunMethod Run;
A()
{
Run = RunOff;
}
void SetOn(bool value)
{
if (value)
Run = RunOn;
else
Run = RunOff;
}
void RunOn(int)
{
// RunOn stuff here
}
void RunOff(int)
{
// RunOff stuff here
}
};
所以我可以调用,Run()并且在函数调用之间会有一个切换,我认为这比仅仅这样做更有效:
if (on)
RunOn();
else
RunOff();
不知道怎么办!
回答
您的成员函数指针typedef是错误的(尽管显示的代码中存在其他问题)。你需要
typedef void(A::*RunPtr)(int);
或者你可以通过关键字A的帮助为类的成员函数指针提供别名,如下所示:using
using RunPtr = void(A::*)(int);
RunPtr RunMethod;
现在, SetOn您可以按如下方式进行成员指针分配
void SetOn(bool value)
{
RunMethod = value ? &A::RunOn : &A::RunOff;
}
现在,为了调用存储的成员函数指针,您可以/可以提供Run如下成员函数:
void Run(int arg)
{
std::invoke(RunMethod, this, arg);
// do something...
}
对成员函数的调用有点棘手。但是,这可以使用更通用的std::invokefrom <functional>header (Since c++17 ) 来完成。
这是完整的示例:
#include <iostream>
#include <functional> // std::invoke
class A
{
using RunPtr = void(A::*)(int);
// or with typedef
// typedef void(A::*RunPtr)(int);
RunPtr RunMethod;
public:
void SetOn(bool value)
{
RunMethod = value ? &A::RunOn : &A::RunOff;
}
void Run(int arg)
{
std::invoke(RunMethod, this, arg);
// do something...
}
void RunOn(int arg) { std::cout << "RunOn: " << arg << "n"; }
void RunOff(int arg) { std::cout << "RunOff: " << arg << "n"; }
};
int main()
{
A obj;
obj.SetOn(true);
obj.Run(1); // prints: RunOn: 1
obj.SetOn(false);
obj.Run(0); // prints: RunOff: 0
}
(见演示)
回答
一旦您修复了其中的语法错误,您的代码就可以正常工作,即:
-
Class需要是class。 -
in
RunMethod Run;,RunMethod不是类型,而是成员变量。您打算改为使用RunPtr Run;(并摆脱RunMethod),但这对您来说效果不佳(请参阅下文了解原因)。 -
在
Run = RunOn;and 中Run = RunOff;,您需要完全限定方法名称,并在其前面加上&运算符,例如Run = &A::RunOn;.
请尝试以下操作:
class A {
public:
typedef void (A::*RunPtr)(int);
RunPtr Run;
A()
{
Run = &A::RunOff;
}
void SetOn(bool value)
{
if (value)
Run = &A::RunOn;
else
Run = &A::RunOff;
}
void RunOn(int param)
{
//RunOn stuff here
}
void RunOff(int param)
{
//RunOff stuff here
}
};
但是请注意,即使您可以Run像这样使用公共方法指针,调用者仍然需要使用operator.*或operator->*实际调用它,这看起来不太好,例如:
A a;
(a.*a.Run)(...);
在线演示
如果你想能够Run()像那样调用,a.Run(...)那么你必须Run()成为一个标准方法,并让它在内部使用一个方法指针,例如:
class A {
typedef void (A::*RunPtr)(int);
RunPtr RunMethod;
public:
A()
{
RunMethod = &A::RunOff;
}
void SetOn(bool value)
{
if (value)
RunMethod = &A::RunOn;
else
RunMethod = &A::RunOff;
}
void RunOn(int param)
{
//RunOn stuff here
cout << "RunOn: " << param << endl;
}
void RunOff(int param)
{
//RunOff stuff here
cout << "RunOff: " << param << endl;
}
void Run(int param)
{
(this->*RunMethod)(param);
}
};
A a;
a.Run(...);
在线演示