繁体   English   中英

如何从静态成员函数调用指向成员函数的指针?

[英]How to invoke pointer to member function from static member function?

我需要获得一个由标准函数指针调用的成员函数,所以我尝试抽象这样的东西:

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-pointer作为数据。

......我不希望像AB这样A类有静态成员。 所以我的想法是创建一个类Sample的接口,它由AB扩展。

我的问题是我不知道如何从Executor::execute函数内部调用指向成员函数的指针。

问题是,你需要两个对象里面execute -一个实例Executor将提供func ,另一个是(从派生的类)的实例Samplefunc将被调用。 所以你必须将对象存储在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)() )标识类中的函数,但不存储该对象。 您仍然需要提供一个来调用该函数。

您还需要传递一个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);
}

如果你想与外部系统调用进行交互,你基本上必须自己重新发明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 ++中,我们将整个系统调用调用包装在一个内部封装生命周期管理的类中。

您可以为带参数的成员函数添加更多特化; 你只需要在状态中存储参数的副本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM