2013-02-25 2 views
4

Я могу выбирать между указателями функций и объектами подкласса. Чтобы было ясно, скажите, что я должен уведомить какой-то объект о каком-либо действии (например, таймер); обратитесь к следующим двум вариантам (очень базовый код для демонстрационных целей):C++ Указатели функций против подклассов

Version 1

typedef void TimerCallback(void *args); 
class Timer{ 
public: 
    Timer(); 
    ~Timer(); 
    void schedule(TimerCallback *callback, void *args, long timeout)=0; 
    void cancel(); 
}; 

Версию 2

class TimerTask{ 
    public: 
    TimerTask(); 
    virtual ~TimerTask(); 
    void timedout()=0; 
}; 
class Timer{ 
    public: 
    Timer(); 
    virtual ~Timer(); 
    void schedule(TimerTask *callback, long timeout)=0; 
    void cancel(); 
}; 

который один путь стандарта C++ и какой из них эффективен? Пожалуйста, дайте мне знать, если у вас есть другие предложения в этом отношении.

Пожалуйста, дайте мне знать, если я не понимаю в этом отношении.

Благодаря

+0

Google «шаблон наблюдателя». –

+0

'TimerTask' по сути является интерфейсом, и он часто используется в таких сценариях. С другой стороны, использование указателя функции дает дополнительную гибкость, поскольку вы можете обернуть что-либо в функцию/функтор. Кроме того, с интерфейсом вам обычно придется позаботиться об удалении объекта (если вы не используете интеллектуальные указатели), который вам не нужен с указателями fn. –

+0

Ваш вопрос не имеет ни одного ответа ... это зависит от желаемого стиля. Но в целом вы должны взглянуть на разные предложения. – fen

ответ

14

Я бы сказал std::function и std::bind. Тогда не имеет значения, хотите ли вы использовать унаследованные классы, автономные функции, функции-члены или lambdas.


Кстати, если кому-то интересно, я сделал простое событие таймера обработки некоторое время назад, как ответ на другой вопрос. Это демонстрирует использование, например, std::function и std::bind: https://stackoverflow.com/a/11866539/440558.

+2

+1 - этот ответ наиболее верен духу C++ –

+0

Спасибо Joachim. Это очень полезный совет. Я посмотрю на это. – user630286

+0

Хотя я собираюсь реализовать объектно-ориентированный подход для этой реализации, это тот маршрут, который я должен взять в конечном итоге. Спасибо за все ваши ответы. – user630286

2

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

На мой взгляд, использование объектов, а не указателей функций, является чище и вообще лучшим способом сделать.

Вы также можете попытаться использовать visitor pattern, чтобы сделать код еще лучше и более гибким.

Вы также можете рассмотреть publisher/subscriber pattern.

+2

C++ - это язык с несколькими парадигмами, поэтому я был бы осторожен, заявляя, что он использует объектно-ориентированное программирование. На самом деле, на мой взгляд, невозможно дать правильный ответ, не зная больше о остальной системе (например, кто удалит экземпляры обратного вызова, когда и как) –

+0

@ZdeslavVojkovic на основе кода, который мне дал, я сделал точка; Я согласен, что это спорный вопрос, но как я уже говорил, что это мнение. По моему опыту, я знаю, что чаще всего использование указателей функций является ненужным и трудным для этого, используя объекты. Не говоря уже о повышенной сложности для поддержания кода. – Dariusz

+0

Я согласен с указателями на функции, если они используются на языке C, но правильный ответ - это то, что предложил Йоахим Пилеборг (ИМО, конечно) –

4

Я думаю, что лучше использовать boost(or std since C++11)::function для проведения обратного вызова и boost::bind, чтобы связать его аргументы или использовать boost::signal. Это было бы более общее и подробное решение по цене действительно небольшого штрафа.

http://www.boost.org/doc/libs/1_53_0/doc/html/signals2.html

0

Оба работают. Ваш первый - это «C-стиль» и где-то потребуется статическая функция. Вторая версия - «C++ style» и позволяет использовать экземпляр TimerTask.

Как правило, следует использовать версию 2, поскольку она устраняет необходимость в статической функции.

+1

, но он представляет необходимость удаления объекта задачи. Кроме того, в современном C++ легко переносить почти что-либо в функцию или использовать лямбда. –

+0

Спасибо, ребята. Как я упоминал в оригинальном примере, в случае реализации таймера я не хочу привязывать задачу к одной реализации функции, которая имеет место со статическими функциями. Если я реализую подклассу TimerTask, я дам разработчику что-нибудь сделать с таймаутом. Задача может отличаться в зависимости от модуля. Это неправильно? – user630286

+0

Когда кто-то предоставляет указатель, они должны нести ответственность за его доступность до тех пор, пока это не понадобится, и очистите его после завершения задачи (за исключением случаев, когда QT указывает родительский объект, который затем примет новый объект и очистит его после использования). Это тоже не так? – user630286

1

Функциональный указатель эффективно предотвращает использование замыканий - назначение методов обработчику событий (это не полностью true, но это будет ограничивать вас таким образом, что это решение не очень полезно).

Я бы проголосовал за объектно-ориентированный подход. Если вы используете C++ 11, вы можете значительно упростить код:

#include <cstdio> 
#include <functional> 

class Emitter 
{ 
private: 
    std::function<void(int)> eventHandler; 

public: 
    void SetEventHandler(std::function<void(int)> newEventHandler) 
    { 
     eventHandler = newEventHandler; 
    } 

    void EmitEvent() 
    { 
     eventHandler(42); // + error-checking 
    } 
}; 

class Handler 
{ 
private: 
    void HandleEvent(int i) 
    { 
     printf("Event handled with i == %d\n", i); 
    } 

public: 
    void AttachEmitter(Emitter & e) 
    { 
     e.SetEventHandler([this](int i) { HandleEvent(i); }); 
    } 
}; 

int main(int argc, char * argv[]) 
{ 
    Emitter e; 
    Handler h; 

    h.AttachEmitter(e); 
    e.EmitEvent(); 
} 
Смежные вопросы