指向派生类方法的指针列表

时间:2013-12-23 11:58:40

标签: c++

我正在尝试在C ++中创建以下内容:

class A {
    SpecialContainer<SpecialType> list_of_callables;

    void add_to_container(SpecialType *method); // adds method to the SpecialContainer
};

class B : public A {
    void method_1();
};

使用例如

method_1的指针插入容器中
a.add_to_container(&B::method_1)

因此在A中使用例如

在迭代中调用
# pseudo code
for item in container
    (this->*item)();

(请注意,A未定义method_1)。

我的问题是:这是否可行,即使使用void*,也可以使用升级库 C / C ++黑客?如果是,怎么样?

(如果答案很明显,我很抱歉,最近我从Python回来了。)


到目前为止,我尝试使用

typedef void (A::*SpecialType)();

SpecialContainer一个std::vector,但自method_1以来没有成功 显然来自B,即我必须打电话

add_to_container(&B::method_1)

这是一个无效的编译。

2 个答案:

答案 0 :(得分:1)

您无法通过指向成员函数的指针将指针混合到函数中,因此您无法以这种方式实现回调列表。

我已经多次以事件类的形式实现了这种列表。我对该问题的解决方案是以两种不同的方式分派全局处理程序和成员处理程序,并在调用处理程序时使用动态绑定:

    //C#-like event class. It supports global functions and member functions as handlers

    template<typename SENDER , typename ARGUMMENTS = void>
    class event
    {
    public:
            typedef SENDER& sender_param_type;
            typedef ARGUMMENTS& argumments_param_type;

    private:
            struct handler_data
            {
                    virtual void dispatch( sender_param_type , argumments_param_type ) = 0;
                    virtual ~handler_data() {}
            };

            struct global_handler_data : public handler_data
            {
                    typedef std::function<void(sender_param_type , argumments_param_type)> global_handler_type;

                    global_handler_type handler;

                    global_handler_data( const global_handler_type& handlerrr ) : handler( handlerrr ) {}

                void dispatch( sender_param_type sender , argumments_param_type argumments )
                    {
                            handler( sender , argumments );
                    }
            };

            template<typename HANDLER_CLASS>
            struct member_handler_data : public handler_data
            {
                    typedef void(HANDLER_CLASS::*member_handler_type)( sender_param_type , argumments_param_type);

                    member_handler_type handler;
                    HANDLER_CLASS& handler_instance;

                    member_handler_data( HANDLER_CLASS& handlerrr_instance , const member_handler_type& handlerrr ) : handler_instance( handlerrr_instance ) , handler( handlerrr ) {} 

                    void dispatch( sender_param_type sender , argumments_param_type argumments )
                    {
                            (handler_instance.*handler)( sender , argumments );
                    }
            };

            std::vector<std::unique_ptr<handler_data>> _handlers;

    public:
            void add_handler( const typename global_handler_data::global_handler_type& handler )
            {
                    _handlers.push_back( std::unique_ptr<handler_data>( new global_handler_data( handler ) ) );
            }

            template<typename HANDLER_CLASS>
            void add_handler( HANDLER_CLASS& handler_instance , const typename member_handler_data<HANDLER_CLASS>::member_handler_type& handler )
            {
                    _handlers.push_back( std::unique_ptr<handler_data>( new member_handler_data<HANDLER_CLASS>( handler_instance , handler ) ) );
            }

            void raise_event( sender_param_type sender , argumments_param_type argumments )
            {
                    for(auto& handler : _handlers )
                    {
                            handler->dispatch( sender , argumments );
                    }
            }
    };



    //Non-args evets specialization:

    template<typename SENDER>
    class event<SENDER,void>
    {
    public:
            typedef SENDER& sender_param_type;

    private:
            struct handler_data
            {
                    virtual void dispatch( sender_param_type ) = 0;
                    virtual ~handler_data() {}
            };

            struct global_handler_data : public handler_data
            {
                    typedef std::function<void(sender_param_type)> global_handler_type;

                    global_handler_type handler;

                    global_handler_data( const global_handler_type& handlerrr ) : handler( handlerrr ) {}

                void dispatch( sender_param_type sender )
                    {
                            handler( sender );
                    }
            };

            template<typename HANDLER_CLASS>
            struct member_handler_data : public handler_data
            {
                    typedef void(HANDLER_CLASS::*member_handler_type)( sender_param_type );

                    member_handler_type handler;
                    HANDLER_CLASS& handler_instance;

                    member_handler_data( HANDLER_CLASS& handlerrr_instance , const member_handler_type& handlerrr ) : handler_instance( handlerrr_instance ) , handler( handlerrr ) {} 

                    void dispatch( sender_param_type sender )
                    {
                            (handler_instance.*handler)( sender );
                    }
            };

            std::vector<std::unique_ptr<handler_data>> _handlers;

    public:
            void add_handler( const typename global_handler_data::global_handler_type& handler )
            {
                    _handlers.push_back( std::unique_ptr<handler_data>( new global_handler_data( handler ) ) );
            }

            template<typename HANDLER_CLASS>
            void add_handler( HANDLER_CLASS& handler_instance , const typename member_handler_data<HANDLER_CLASS>::member_handler_type& handler )
            {
                    _handlers.push_back( std::unique_ptr<handler_data>( new member_handler_data<HANDLER_CLASS>( handler_instance , handler ) ) );
            }

            void raise_event( sender_param_type sender )
            {
                    for(auto& handler : _handlers )
                    {
                            handler->dispatch( sender );
                    }
            }
    };

如您所见,该类旨在使用两个参数调度事件:对引发事件的对象的引用以及事件参数。
您可以使用C ++ 11 variadic-templates而不是仅使用一个聚合事件参数,但我这样做是因为该类必须与MSVC11兼容。

该类提供了完全相同的界面来管理全局处理程序和成员处理程序,add_handler()函数以这种方式重载。唯一的区别是成员处理程序需要调用一个对象,因此事件的处理程序在注册成员处理程序时存储对用户指定的调用者对象的引用。

最后,该类专门用于允许用户创建没有参数的事件。

以下是其用法示例:

class rabbit
{
    void jump()
    {
         up.raise
    }
}

答案 1 :(得分:1)

add_to_container(&B::method_1)

这只有在method_1是B的静态成员时才有效。以下代码适用于我(除了链接和std :: vector而不是容器类):

class A {
public:
    typedef void (*SpecialType)();

    std::vector<SpecialType> list_of_callables;

    void add_to_container(SpecialType method);
};

class B : public A {
public:
    static void method_1();
};

int main()
{
    A a;
    a.add_to_container(&B::method_1);
    return 0;
}

如果您想要绑定到B的特定实例的函数,请查看std::bind如果您使用的是C ++ 11,或boost::bind用于较旧的C ++。