2014-10-31 5 views
2

Этот вопрос задан раньше, но не отвечает удовлетворительно.() Перегрузка оператора

У меня есть класс, который действует как обработчик события, и я хотел бы иметь хороший синтаксис для вызова обработчика события за пределами события. Это сводится к переопределению оператора(). Я в настоящее время имею

class EventHandler 
{ 
public: 
    void Call(void* sender, EventArgs e); 

    void operator() (void* sender, EventArg e){ Call(sender, e); } 
}; 

который отлично работает. Я могу вызвать обработчик события через

EventHandler EH; 
EH(nullptr, EventArgs::Empty()); 

Моя проблема заключается в том, что я обычно хранить обработчик событий в куче, поэтому мне нужно

EventHandler* EH; 
EH(nullptr, EventArgs::Empty()); // error but this is the syntax I'm hoping for 

, но это может быть сделано только с

EventHandler* EH; 
(*EH)(nullptr, EventArgs::Empty()); // no error 

Как я могу переопределить оператор(), чтобы он работал с указателем на объект EventHandler? Я видел некоторые вещи, которые выглядят как перегрузка оператора ->(), а не только оператор(), но я не смог его понять.

+1

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

+0

Вы можете превратить ненулевой указатель в ссылку, чтобы получить синтаксис, который вы ищете. – quamrana

ответ

7

Оператор ->() не существует.

Существует два способа вызова оператора.

EventHandler* EH; 
(*EH)(nullptr, EventArgs::Empty()); 

или

EventHandler* EH; 
EH->operator()(nullptr, EventArgs::Empty()); 

Это работает точно так же, как operator= или любого другого оператора

0

Вы не можете. EventHandler* - это указатель на тип, который просто не вызываем.

2

«Моя проблема заключается в том, что я обычно хранить обработчик событий в куче, поэтому мне нужно "

Есть ли причина для этого? Если EH включает в себя большое количество состояний, то, возможно, вы могли бы создать класс-оболочку, который помещал бы состояние в кучу, но сам был выделен как объект. Это позволило бы перегрузить operator()() и получить желаемый синтаксис при пересылке в базовую реализацию. В основном рефакторинг для Pimpl, чтобы получить синтаксис, который вы хотите в объектах, которые вы используете в своем интерфейсе.

+0

Я упрощал ситуацию. Дело не в том, что это всегда в куче. Это то, что я обычно имею дело со ссылкой, которая была передана. –

0

Вы можете использовать другой функтор в качестве обертки, вам нужно будет просто назвать его по-другому.

struct EventHandlerCaller 
{ 
    void operator() (EventHandler* eh, void* sender, EventArg& e) 
    { 
    eh->operator()(nullptr, sender, e); 
    } 
} 

static EventHandlerCaller caller; 
EventHandler* EH; 
caller(eh, nullptr, EventArgs::Empty()); 
1

Часто бывает полезно обернуть детали распределения кучи в обычном типе и использовать обычный тип, а не указатель.

class EventHandler_Impl { 
public: 
     void Call(void* sender, EventArgs e); 

     void operator() (void* sender, EventArg e){ Call(sender, e); } 
}; 

тогда мы пишем:

struct EventHandler { 
    void operator()(void* sender, EventArg e){ (*pImpl)(sender, e); } 
private: 
    std::unique_ptr<EventHandler_Impl> pImpl; 
}; 

у нас есть "регулярный" тип EventHandler, который хранит указатель на "актуальный" класс. У этого есть методы, которые продвигаются к pImpl.

Состояние этого класса - всего лишь один указатель.Он автоматически удаляет pImpl, когда он выходит из сферы действия. У std::unique_ptr есть накладные расходы указателя (который вы сохранили вместо этого), за исключением того, что он разрушает объект pImpl, когда он выходит за пределы области видимости.

Вы можете сделать это только для перемещения или вручную реализовать конструктор копирования (добавив к интерфейсу _Impl возможность клонирования).

Немного шаблона.

Вы можете покончить с методами записи в _Impl, просто нарисуя их в обычном типе и имея доступ к ним только через указатель pImpl, если вы выберете.