Function hooking in C++?

后端 未结 7 687
一整个雨季
一整个雨季 2020-12-13 02:11

With \"hooking\" I mean the ability to non-intrusively override the behavior of a function. Some examples:

  • Print a log message before and/or after the function
7条回答
  •  情歌与酒
    2020-12-13 02:40

    If you're talking about causing a new method to be called before/after a function body, without changing the function body, you can base it on this, which uses a custom shared_ptr deleter to trigger the after-body function. It cannot be used for try/catch, since the before and after need to be separate functions using this technique.

    Also, the version below uses shared_ptr, but with C++11 you should be able to use unique_ptr to get the same effect without the cost of creating and destroying a shared pointer every time you use it.

    #include 
    #include 
    #include 
    #include 
    
    template 
    class base_wrapper
    {
    protected:
      typedef T wrapped_type;
    
      Derived* self() {
        return static_cast(this);
      }
    
      wrapped_type* p;
    
      struct suffix_wrapper
      {
        Derived* d;
        suffix_wrapper(Derived* d): d(d) {};
        void operator()(wrapped_type* p)
        {
          d->suffix(p);
        }
      };
    public:
      explicit base_wrapper(wrapped_type* p) :  p(p) {};
    
    
      void prefix(wrapped_type* p) {
         // Default does nothing
      };
    
      void suffix(wrapped_type* p) {
         // Default does nothing
      }
    
      boost::shared_ptr operator->() 
      {
        self()->prefix(p);
        return boost::shared_ptr(p,suffix_wrapper(self()));
      }
    };
    
    
    
    
    template
    class timing_wrapper : public base_wrapper< T, timing_wrapper >
    {
      typedef  base_wrapper< T, timing_wrapper > base;
      typedef boost::chrono::time_point > time_point;
    
      time_point begin;
    public:
      timing_wrapper(T* p): base(p) {}
    
    
      void prefix(T* p) 
      {
        begin = boost::chrono::system_clock::now();
      }
    
      void suffix(T* p)
      {
        time_point end = boost::chrono::system_clock::now();
    
        std::cout << "Time: " << (end-begin).count() << std::endl;
      }
    };
    
    template 
    class logging_wrapper : public base_wrapper< T, logging_wrapper >
    {
      typedef  base_wrapper< T, logging_wrapper > base;
    public:
      logging_wrapper(T* p): base(p) {}
    
      void prefix(T* p) 
      {
        std::cout << "entering" << std::endl;
      }
    
      void suffix(T* p) 
      {
        std::cout << "exiting" << std::endl;
      }
    
    };
    
    
    template