使用接口或函数对象进行回调?

PoP*_*PoP 9 c++ design-patterns interface c++11

在OO,一个通常与接口实现回调:(粗示例)

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_;
}
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.使用C++ 11,另一种方法是让CustomSocket只接收std :: function对象的实例.它并不关心它的实现位置,或者即使对象是非null值:

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_;
}
Run Code Online (Sandbox Code Playgroud)

现在问题如下:
1.性能影响如何?我猜一个虚函数调用比调用一个函数对象更快,但速度有多快?我正在实现一个快速消息系统,我宁愿避免任何不必要的性能损失.
2.在软件工程实践方面,我不得不说我更喜欢第二种方法.代码更少,文件更少,更简洁:没有接口类.更灵活:您只能通过设置某些功能对象并将其他功能对象保留为空来实现接口的子集.或者,您可以在单独的类中实现接口的不同部分,也可以通过自由函数或两者的组合(而不是在单个子类中)实现.此外,CustomSocket可以被任何类使用,而不仅仅是IMsgProcessor的子类.这是一个在我看来,很有优势.
你说什么?你认为这些论点存在根本缺陷吗?

Joh*_*ela 3

您可以两全其美

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

};
Run Code Online (Sandbox Code Playgroud)

然后你可以这样使用

Socket s(CreateMessageProcessor([](const Message& msg){...}));
Run Code Online (Sandbox Code Playgroud)

或者为了更容易地向 Socket 添加另一个构造函数

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


};
Run Code Online (Sandbox Code Playgroud)

那么你可以做

Socket s([](const Message& msg){...});
Run Code Online (Sandbox Code Playgroud)

并且仍然具有与虚函数调用相同的效率

  • 呃,赤裸裸的“新”!掩盖你的耻辱!...更严重的是,`std::function` 内部使用内置虚拟调度或带有函数指针、`void*` 和函数模板的手动实现。 (4认同)