如何从静态成员函数调用指向成员函数的指针?
Posted
技术标签:
【中文标题】如何从静态成员函数调用指向成员函数的指针?【英文标题】:How to invoke pointer to member function from static member function? 【发布时间】:2014-10-28 09:25:16 【问题描述】:我需要获取一个由标准函数指针调用的成员函数,所以我尝试抽象如下:
class Sample
public:
virtual void doSomething(void) = 0;
;
class A : public Sample
void doSomething(void); // details omitted
;
class B : public Sample
void doSomething(void); // details omitted
;
class Executor
public:
Executor(Sample *sample)
: func(&sample->doSomething)
static void *execute(void *data)
Executor *pX = data;
(pX->*func)(); // error invalid access of func from static function
(pX->*pX->func)(); // error pointer to member type 'void (Sample::)()'
// incompatible with object type 'Executor'
private:
void (Sample::*func)(void);
;
int main(void)
A myA;
B myB;
Executor x0(&myA);
Executor x1(&myB);
externallyInvoke(&Executor::execute, &x0);
externallyInvoke(&Executor::execute, &x1);
externallyInvoke
是一个Linux系统调用,它接受一个函数指针和一个数据指针。
我想使用静态成员函数和 this 指针作为数据。
... 我不希望像 A
或 B
这样的类有静态成员。所以我的想法是创建一个类似Sample
类的接口,由A
和B
扩展。
我的问题是我不知道如何从 Executor::execute
函数内部调用指向成员函数的指针。
【问题讨论】:
无法从静态函数访问成员变量 - 有什么不清楚的地方? 【参考方案1】:问题是execute
中需要两个对象——一个是Executor
的实例,它将提供func
,另一个是Sample
的实例(派生自)Sample
987654325@ 将被调用。所以你必须在Executor
中存储对象,而不是函数:
class Executor
public:
Executor(Sample *sample)
: obj(sample)
static void *execute(void *data)
Executor *pX = static_cast<Executor*>(data);
pX->obj->doSomething();
private:
Sample *obj;
;
int main() // note that `void main()` is not legal C++
A myA;
B myB;
Executor x0(&myA);
Executor x1(&myB);
externallyInvoke(&Executor::execute, &x0);
externallyInvoke(&Executor::execute, &x1);
指向成员函数的指针(例如您原来的void (Sample::*func)()
)标识类中的函数,但不存储对象。您仍然需要提供一个来调用该函数。
【讨论】:
不应该是x0(myA)
是x0(&myA)
?
@Wimmel 是的,当然,我在问题中修复之前从 OP 复制了它。谢谢。
@Angew 我显然是想重新发明一个仿函数,但是您的解决方案非常干净,因此:可爱 :) THX【参考方案2】:
如果你想与外部系统调用交互,你基本上必须自己重新发明std::function
。没问题,在 Stack Overflow,我们是重塑现有技术的大师。所以...
一、界面:
struct FunctionStateBase
virtual ~FunctionStateBase()
virtual void Invoke() = 0;
;
extern "C" void InvokeAndDelete(void * data)
auto state = static_cast<FunctionStateBase *>(data);
state->Invoke();
delete state;
这是你如何使用它:
externallyInvoke(&InvokeAndDelete, MakeFunction(&A::doSomething, &myA));
现在我们需要实现MakeFunction
:
template <typename> struct FunctionState;
template <typename C, typename R>
struct FunctionState<R (C::*)()> : FunctionStateBase
R (C::ptmf_*)();
C * obj_;
FunctionState(R (C::ptmf*)(), C * obj) : obj_(obj), ptmf_(ptmf)
virtual void Invoke() (C->ptmf_)();
;
template <typename C, typename R>
FunctionState<R (C::*)()> MakeFunction(R (C::*ptmf)(), C * obj)
return new FunctionState<R (C::*)()>(ptfm, obj);
此时我们正在手动管理函数包装器的生命周期,请注意InvokeAndDelete
实际上取得了函数状态的所有权。在适当的 C++ 中,我们会将整个系统调用调用包装在一个类中,该类将在内部封装生命周期管理。
您可以为接受参数的成员函数添加进一步的特化;您只需要在状态中存储参数的副本。
【讨论】:
【参考方案3】:您还需要传递Sample
的实例来调用函数(因为它是指向Sample
成员的指针)。有几种方法可以带来实例。您可以使其成为Executor
的成员,将std::pair*
作为data
传递,或者您可以将函数指针和实例组合为仿函数。这是后者的基于 lamda 的方法。 lamda 的优点是用途更广。可以做的不仅仅是调用一个类的一个成员。作为奖励,这种方法不会避免可见性规则,尽管这意味着 doSomething
可能不是私有的(或者必须通过父指针调用)。
template<class F>
class Executor
F f;
public:
Executor(F f): f(f)
static void *execute(void *data)
Executor<F> *pX = static_cast<Executor<F>*>(data);
pX->f();
return this; // not quite sure what you intend to return, but just to make this a well formed function...
;
int main()
A myA;
B myB;
auto callback0 = [myA]
myA.doSomething();
;
auto callback1 = [myB]
myB.doSomething();
;
Executor<decltype(callback0)> x0(callback0);
Executor<decltype(callback1)> x1(callback1);
externallyInvoke(&Executor::execute, &x0);
externallyInvoke(&Executor::execute, &x1);
【讨论】:
func
是成员,不能在static
方法中使用。
@user657267 啊,明白了。修正了答案。
如何解决这个问题?他想通过static
方法调用成员函数指针,这根本不可能,使其public
没有任何改变。
@user657267,该死的不是我的日子。我没有注意到它不仅是一个成员,而且还是一个指向另一个类的成员函数的指针。以上是关于如何从静态成员函数调用指向成员函数的指针?的主要内容,如果未能解决你的问题,请参考以下文章