Список указателей на методы производных классов

0

Я пытаюсь создать в 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)

и, следовательно, вызываться на итерации внутри А, используя, например,

# pseudo code
for item in container
    (this->*item)();

(Обратите внимание, что A не определяет method_1).

Мой вопрос: это даже возможно сделать, даже если с void*, boost lib или C/C++ взломать? Если да, то как?

(Прошу прощения, если ответ очевиден, я недавно вернулся с Python).


До сих пор я пытался использовать

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

и SpecialContainer - std::vector, но без успеха, так как method_1, очевидно, из B, то есть я должен был бы позвонить

add_to_container(&B::method_1)

который является недопустимой компиляцией.

Теги:

2 ответа

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++.

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 );
                    }
            }
    };

Как вы можете видеть, класс предназначен для отправки событий с двумя параметрами: ссылка на объект, который поднял событие, и параметры события.
Вы можете использовать С++ 11 variadic-templates вместо одного только агрегатного параметра события, но я сделал это таким образом, потому что класс должен был быть совместим с MSVC11.

Класс предоставляет точно такой же интерфейс для управления глобальными обработчиками и обработчиками элементов, add_handler() функция add_handler() перегружается таким образом. Единственное отличие состоит в том, что для обработчиков элементов требуется один объект для вызова, поэтому обработчик события сохраняет ссылку на объект вызывающего объекта, указанный пользователем, когда регистрирует обработчик элемента.

Наконец, класс специализирован, чтобы пользователь мог создавать события без параметров.

Вот пример его использования:

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню