簡體   English   中英

C ++:在另一個對象中存儲指向某個對象的成員函數的指針

[英]C++: Store pointer to a member function of an object in another object

我有一個類,它將在某些情況下調用用戶指定的功能。 因此,該類具有方法void setExternalPostPaintFunction(void(*function)(QPainter&)); 可以用來“注冊”功能。 然后將在這種情況下調用此函數:

class A {
    public:
        void setExternalPostPaintFunction(void(*function)(QPainter&));
    private:
        void (*_externalPostPaint)(QPainter&);
        bool _externalPostPaintFunctionAssigned;
};

函數指針保存在成員變量_externalPostPaint setExternalPostPaintFunction的實現如下所示:

void A::setExternalPostPaintFunction(void(*function)(QPainter&)) {
    _externalPostPaint = function;
    _externalPostPaintFunctionAssigned = true;
}

現在,這可以正常使用。 但是,我希望也能夠將指針傳遞給對象的成員函數 據我所知,在這種情況下,我還必須傳遞並存儲指向該對象的指針。 但是,我不知道其他對象將具有哪種類型。 所以我想我被迫使用模板。 我已經想到過這樣的事情:

class A {
    public:
        template <typename T>
        void setExternalPostPaintFunction(void(T::*function)(QPainter&), T* object);
    private:
        void (T::*_externalPostPaint)(QPainter&);       //<- This can't work!
        bool _externalPostPaintFunctionAssigned;
};

這樣,我可以將一個函數指針和一個對象指針傳遞給setExternalPostPaintFunction ,並且可能能夠在該函數內部的對象上調用該函數。 但是我無法將其存儲在變量_externalPostPaint因為類型T僅在調用函數setExternalPostPaintFunction時才推導,因此我無法擁有依賴於此類型的成員變量,因為我的成員變量的類型具有要知道創建對象的時間,除此之外不能更改,但是必須在分配了新功能的情況下(可能是不同類型對象的成員功能)。

那么執行此操作的正確方法是什么? 我不太適合使用模板和函數指針,因此我可能忽略了一些東西。

另一個選擇當然是使用虛擬成員函數創建函子類,該成員函數可以在派生類中被覆蓋,然后通過+存儲該類型的對象指針而不是函數指針。 但是,如果有可能,我會以某種方式更喜歡我的方法。

編輯:解決方案

TartanLlama通過建議使用std::function使我走上了正確的軌道。 這是我解決的方法:

class A {
    public:
        template <typename T>
        void setExternalPostPaintFunction(T* object, void(T::*function)(QPainter&)) {
            _externalPostPaint = std::bind(function, object, std::placeholders::_1);
            _externalPostPaintFunctionAssigned = true;
        }
        void setExternalPostPaintFunction(std::function<void(QPainter&)> const& function);
    private:
        std::function<void(QPainter&)> _externalPostPaint;
        bool _externalPostPaintFunctionAssigned;
};

如您所見,函數/成員函數的指針現在存儲在std::function<void(QPainter&)>對象中。 優點是std::function基本上可以存儲任何可調用目標。 然后有兩個重載:一個重載可用於任何std::function對象,該對象也接受例如普通的函數指針(因為預期的std::function會由此隱式構造),另一個重載用於具有在對象上被調用(為方便起見)。 后者被實現為模板。 這使用std::bind在對象(用戶通過)上創建該成員函數(用戶通過)的調用的std::function對象。

需要在源文件中實現std::function的重載是這樣的:

void ImageView::setExternalPostPaintFunction(std::function<void(QPainter&)> const& function) {
    _externalPostPaint = function;
    _externalPostPaintFunctionAssigned = true;
}

現在,在類A的代碼中調用該存儲的函數非常簡單:

//canvas is a QPainter instance    
if (_externalPostPaintFunctionAssigned) _externalPostPaint(canvas);

想要將成員函數注冊為回調函數的用戶只需執行以下操作:

//_imageView is an instance of "A"
//"MainInterface" is the type of "this"
_imageView->setExternalPostPaintFunction(this, &MainInterface::infoPaintFunction);

或者,如果它不是成員函數,而是普通函數:

void someFunction(QPainter& painter) {
    //do stuff
}

_imageView->setExternalPostPaintFunction(&someFunction);

或者,他可以顯式創建一個std::function對象並傳遞它:

std::function<void(QPainter&)> function = [&](QPainter& painter){ this->infoPaintFunction(painter); };
_imageView->setExternalPostPaintFunction(function);

奇跡般有效。

您可以使用std::function

class A {
    public:
        //PostPaintFun can be anything which acts as a function taking a QPainter&
        //Could be a lambda, function pointer, functor, etc.
        using PostPaintFun = std::function<void(QPainter&)>;
        void setExternalPostPaintFunction(PostPaintFun fun);
    private:
        //Names beginning with an underscore are reserved, don't use them
        //Ending with an underscore is fine
        PostPaintFun fun_;
        bool externalPostPaintFunctionAssigned_;
};

現在,您可以像這樣使用成員函數:

struct B
{
    void exec(QPainter&) const;
};

void foo() {
    B b;
    a.setExternalPostPaintFunction(
        [b] (QPainter& p) {b.exec(p);}
    );
}

//or inside B
void B::foo() {
    a.setExternalPostPaintFunction(
        [this] (QPainter&p) {this->exec(p);}
    );
 }

我不得不說我更喜歡TartanLlama的答案,但是在這里您可以使用一些適合您的東西。

這可能需要一些工作,但是我相信您會明白的。

struct IFunctionHolder {};                      // Used for pointing to any FunctionHolder
typedef IFunctionHolder* functionHolder_ptr;    // Alias for IFunctionHolder* .

template<typename Function>                     // The template for the actual function holders.
struct FunctionHolder:  public IFunctionHolder
{
    Function function;
};


class A {
    public:
        template <typename T>
        void setExternalPostPaintFunction(void(T::*function)(QPainter&), T* object);
    private:
        functionHolder_ptr *function_holder;            // This memeber can hold eny instantiation of template<> FunctionHolder.
                                                        // Instantiate this member wen calling setExternalPostPaintFunction
        bool _externalPostPaintFunctionAssigned;
};

您可能會有類似以下的代碼:

A some_a;
void some_a.setExternalPostPaintFunction(&SomeInstance::some_fnunction);    // Here take place the instantiation of FunctionHolder.
some_a.function_holder.function(some_painter);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM