繁体   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