Вопрос

typedef void (FunctionSet::* Function)();

class MyFunctionSet : public FunctionSet
{
protected:
    void addFunctions()
    {
        addFunction(Function(&MyFunctionSet::function1));
    }

    void function1()
    {
        // Do something.
    }
};

Метод addFunction добавляет функцию в список базового класса.
которые затем можно перечислить для вызова всех функций.

Есть ли способ упростить (меньше печатать) добавление функций?

Это было полезно?

Решение

Похоже, вы назначаете указатель на функцию-член на функцию производного класса на указатель на функцию-член на функцию базового класса. Ну, это запрещено, потому что это открывает дыру в системе типов. Это неожиданно (по крайней мере, для меня, когда я впервые услышал это). Прочитайте этот ответ для Зачем.

Чтобы ответить на ваш актуальный вопрос - я бы сделал addFunction шаблон:

void addFunctions() {
    addFunction(&MyFunctionSet::function1);
}

Измените static_cast в базовом классе на этот:

template<typename Derived>
void addFunction(void(Derived::*f)()) {
    myFunctions.push_back(static_cast<Function>(f));
}

Лучше использовать Derived, потому что он сообщит вам, действительно ли FunctionSet не является производным от <=>.

Другие советы

Можете ли вы объяснить, чего вы пытаетесь достичь этим?

Это выглядит как довольно плохой дизайн, разве вы не можете иметь абстрактный класс (" интерфейс c ++ "), такой как " Computable " который имеет чисто виртуальную функцию1, подкласс Computable для каждой реализации, а затем MyFunctionSet поддерживает набор Computable?

Есть ли конкретная причина, по которой вы используете указатели на функции?

Итак, я, как правило, не согласен с Ури.

Если вы реализуете шаблон Observer, вам нужно сказать следующее:

" когда объект X выполняет Y, я хочу выполнить код Z ".

Использование подхода, основанного исключительно на абстрактном классе, не лучший способ сделать это. Требование отдельного класса (особенно в C ++) для каждого обработчика событий является излишним. Если вы пришли с Java, вот как они все делают. Однако у Java есть 2 функции, которые делают это только немного раздражающим: анонимный класс и & Quot; instance & Quot; член классы. Это позволяет вам определить несколько обработчиков для нескольких событий в одном классе. Вы должны добавить к методам префикс & Quot; class {& Quot ;, но вы можете это сделать.

C ++ не имеет ни анонимных классов, ни " instance " член классы. Это делает использование абстрактного класса для событий гораздо более громоздким, если у вас есть несколько обработчиков, которым нужно совместно использовать состояние. Вы должны сделать то же самое, что и генерация замыканий вручную, что может довольно быстро раздражать.

.NET использует делегаты для обработки событий, которые в основном являются указателями на безопасные функции типов. Они делают код для обработки событий очень простым. В отличие от указателей на функции в C ++, делегат объединяет указатели на функции-члены и статические указатели на функции. По сути, это может привести к появлению & Quot; this & Quot; параметр любой функции-члена, оставляя указатели на функции, которые выглядят как статические указатели на функции. Это означает, что тип объекта, обрабатывающего событие, не является частью события & Quot; interface & Quot ;. Это делает его очень гибким.

Вы не можете сделать это напрямую, используя указатели на функции-члены C ++, потому что " this " Тип в конечном итоге является частью типа указателя на функцию, что ограничивает ваши обработчики только появлением в текущем классе.

Лучшее решение для C ++ - это гибрид между ними. Вам нужен универсальный интерфейс, подобный следующему:

class EventHandler
{
public:
    virtual void Handle() = 0;
};

А затем реализация для функций-членов, подобных этой

template <class T>
class MemberFuncEventHandler : public EventHandler
{
public:


    MemberFuncEventHandler(T * pThis, void (T::*pFunc)()) : m_pThis(pThis), m_pFunc(pFunc)
    {
    }

    void Handle()
    {
        (m_pThis->*m_pFunc)();
    } 
private:
    T* m_pThis;
    void (T::*m_pFunc)();
};

template <class T>
EventHandler * Handler(T * pThis, void (T::*pFunc)())
{
    return new MemberFuncEventHandler<T>(pThis, pFunc);
}

Вы также можете аналогичным образом определить класс обработчика для статических методов. Тогда вы можете просто делать такие вещи:

Handlers += Handler(obj, &(c1::foo));
Handlers += Handler(obj, &(c2::bar));
Handlers += Handler(blaa); // for static methods...

Полагаю, вы могли бы перегрузить оператор сложения.

Если вы пытаетесь создать систему обратного вызова или что-то в этом роде, я бы порекомендовал библиотеку Boost.Signals.По сути, он объединяет функции и вызывает группу функций по команде (как и любая другая библиотека сигналов), но он также предназначен для работы с Boost.Bind и Boost.Function, которые просто потрясающие.

Пример:

using boost::function
using boost::bind
using boost::signal

void some_other_func();    

Foo a;
Bar b;

signal<void()> sig;

sig.connect(bind(&Foo::foo,&a));
sig.connect(bind(&Bar::bar,&b));
sig.connect(some_other_func);

sig(); // calls -> a.foo(), b.bar(), some_other_func()

Также поддерживает блокировку, сложное управление соединениями и другие полезные вещи.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top