C ++中的函数钩子? [英] Function hooking in C++?
问题描述
hooking我的意思是非侵入性地覆盖函数的行为的能力。一些示例:
- 在函数体之前和/或之后打印日志消息。
- 测量功能的持续时间
- 等...
-
-
-
-
-
-
- Ruby
method_missing
- SWIG 的
%exception
关键字,意味着将所有函数包装在try / catch块中,可以使用(ab) li>
- 这样一个令人难以置信的有用的功能,我不知道为什么它从来没有实现为一个C ++语言功能。是否有任何理由阻止这种情况发生?
- 在C ++程序中实现这些的一些推荐技术或库是什么?
ul>
我在各种编程语言和库中看到过不同的实现:
<
我的问题是:
如果你说的是在函数体之前/之后调用一个新方法,而不改变函数体,你可以它在此上使用自定义 shared_ptr
删除程序来触发后体函数。它不能用于 try / catch
,因为前后需要使用此技术的单独函数。
另外,下面的版本使用 shared_ptr
,但是使用C ++ 11你应该能够使用 unique_ptr
相同的效果,而不需要每次使用时创建和销毁共享指针的成本。
#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){
//默认不做任何操作
};
void suffix(wrapped_type * p){
//默认不做任何事情
}
boost :: shared_ptr< wrapped_type> operator->()
{
self() - > prefix(p);
return boost :: shared_ptr< wrapped_type>(p,suffix_wrapper(self()));
}
};
模板< typename T>
class timing_wrapper:public base_wrapper< T,timing_wrapper< T> >
{
typedef base_wrapper< T,timing_wrapper< T> >基础;
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){}
无效前缀(T * p)
{
begin = boost :: chrono :: system_clock :: now();
}
void suffix(T * p)
{
time_point end = boost :: chrono :: system_clock :: now
std :: cout<< 时间:< (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> >基础;
public:
logging_wrapper(T * p):base(p){}
无效前缀(T * p)
{
std :: cout < 进入<< std :: endl;
}
void suffix(T * p)
{
std :: cout< 出口<< std :: endl;
}
};
template< template< typename>类包装器,类型名T>
wrapper< T> make_wrapper(T * p)
{
return wrapper< T>
}
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;
}
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 body.
- Wrap the function body in a try catch body.
- Measure duration of a function
- etc...
I have seen different implementations in various programming languages and libraries:
- Aspect Oriented Programming
- JavaScript's first class functions
- OOP decorator pattern
- WinAPI subclassing
- Ruby's
method_missing
- SWIG's
%exception
keyword which is meant to wrap all functions in a try/catch block can be (ab)used for the purpose of hooking
My questions are:
- IMO this is such an incredibly useful feature that I wonder why it has never been implemented as a C++ language feature. Are there any reasons that prevent this from being made possible?
- What are some recommended techniques or libraries to implement this in a C++ program?
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;
}
这篇关于C ++中的函数钩子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!