Function hooking in C++?

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 <iostream>
#include <boost/chrono/chrono.hpp>
#include <boost/chrono/system_clocks.hpp>
#include <boost/shared_ptr.hpp>

template <typename T, typename Derived>
class base_wrapper
{
protected:
  typedef T wrapped_type;

  Derived* self() {
    return static_cast<Derived*>(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<wrapped_type> operator->() 
  {
    self()->prefix(p);
    return boost::shared_ptr<wrapped_type>(p,suffix_wrapper(self()));
  }
};




template<typename T>
class timing_wrapper : public base_wrapper< T, timing_wrapper<T> >
{
  typedef  base_wrapper< T, timing_wrapper<T> > base;
  typedef boost::chrono::time_point<boost::chrono::system_clock, boost::chrono::duration<double> > 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 <typename T>
class logging_wrapper : public base_wrapper< T, logging_wrapper<T> >
{
  typedef  base_wrapper< T, logging_wrapper<T> > 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 <template <typename> class wrapper, typename T> 
wrapper<T> make_wrapper(T* p) 
{
  return wrapper<T>(p);
}


class X 
{
public:
  void f()  const
  {
    sleep(1);
  }

  void g() const
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }

};



int main () {

  X x1;


  make_wrapper<timing_wrapper>(&x1)->f();

  make_wrapper<logging_wrapper>(&x1)->g();
  return 0;
}

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)