簡體   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