Callback with interfaces or function objects? [closed]

匆匆过客 提交于 2020-01-12 05:24:41

问题


In OO, one usually implements callbacks with interfaces: (rough example)

class Message {}

class IMsgProcessor {
public:
     virtual void handle_msg(const Message& msg) = 0;
}

class RequestMsgProcessor : public IMsgProcessor {
     virtual void handle_msg(const Message& msg)  {
     // process request message
    }
}

class CustomSocket {
public:
   Socket(IMsgProcessor* p) : processor_(p) {}

   void receive_message_from_network(const Message& msg) {
       // processor_ does implement handle_msg. Otherwise a compile time error. 
       // So we've got a safe design.
       processor_->handle_msg(msg);
   }
private:
   IMsgProcessor* processor_;
}

So far so good. With C++11, another way to do this is to have CustomSocket just receive an instance of std::function object. It does not care where it is implemented or even if the object is a non-null value :

class CustomSocket {
public:
   Socket(std::function<void(const Message&)>&& f) : func_(std:forward(f)) {}

   void receive_message_from_network(const Message& msg) {
       // unfortunately we have to do this check for every msg.
       // or maybe not ...
       if(func_)
            func_(msg);
   }
private:
   std::function<void(const Message&)> func_;
}

Now here are the questions:
1. What about the performance impacts? I'm guessing a virtual function call is faster than calling a function object but how much faster? I'm implementing a fast messaging system and I'd rather avoid any unnecessary performance penalty.
2. In terms of software engineering practices, I have to say I like the second approach better. Less code, fewer files, less clutter: no interface class. More flexibility: you can only implement a subset of the interface by setting some of the function objects and leaving the others null. Or you can have different parts of the interface implemented in separate classes or by free functions or combination of both (instead of in a single subclass). Furthermore, CustomSocket can be used by any class not just subclasses of IMsgProcessor. This is a great advantage, in my opinion.
What do you say? Do you see any fundamental flaw in these argument ?


回答1:


You can have the best of both worlds

template<class F>
class MsgProcessorT:public IMsgProcessor{
  F f_;
  public:
  MsgProcessorT(F f):f_(f){}
  virtual void handle_msg(const Message& msg)  {
      f_(msg);
 }

};
template<class F>
IMsgProcessor* CreateMessageProcessor(F f){
    return new MsgProcessor<T>(f);

};

Then you can either use like this

Socket s(CreateMessageProcessor([](const Message& msg){...}));

Or to make it even easier add another constructor to Socket

class Socket{
...
template<class F>
Socket(F f):processor_(CreateMessageProcessor(f){}


};

Then you could do

Socket s([](const Message& msg){...});

And still have the same efficiency as a virtual function call




回答2:


The interface approach is more traditional but also more verbose: it is clear what a MessageProcessor does and you don't have to check it. Moreover, you can re-use one and the same object with many Sockets.

The std::function approach is more general: anything that accepts the operator()(Message const&) can be used. However, the lack of verbosity has the danger of making the code less readable.

I don't know about performance penalties, but would be surprised if there are significant differences.

I would stick to the interface approach if this is an essential part of your code (as it seems to be).




回答3:


In both of your examples you're actually using interfaces. What's different is the way you define them. In first case the interface is a traditional class with pure virtual functions and in second case the interface is a function reference - it's note much different from a C function pointer from design perspective. In my opinion you can mix both variations according to the specific requirements and consider the pros and cons (which are like you stated) for each new case. Regarding the performance impact, I think the best answer would be to perform testing, compare results and match to your performance requirements.



来源:https://stackoverflow.com/questions/13628187/callback-with-interfaces-or-function-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!