AOP是近年炒得很热,但却用得很少的一门技术,不过这并不能阻止我去学习它。既然能一度炒得火热,必定有过人之处。说AOP是一种思想或许更适合一些,它并不描述哪一种专有的技术,也不指定实现方式。
众所周知,C++没有丰富的动态类型信息,更没有动态生成类的功能(C++类型在编译后就基本上没有类型存在了),所以无法像java一样采用动态代理来实现AOP。
Aspect C++是C++的一个AOP实现,它使用了插入代码的方法。
一个典型的Aspect C++示例需要一个C++源文件(.cpp)、一个Aspect C++源文件(.ah),通过ac++编译器把C++源文件和Aspect C++源文件转换成混合的C++源文件(如果有头文件也会转换),最后通过普通的C++编译器编译出可执行文件。
下面是一个简单的示例:
1、C++源文件:
2、Aspect C++源文件:
简单说明一下:
1、“aspect Action”定义了一个“方面”,名字是“Action”,定义一个方面可以理解为“我关注程序的这个方面”。
2、“advice 切入点:位置”定义一个“处理方法”,在切入点的指定位置上执行代码。切入点可以选择call、execution、construction、destruction,分别表示调用、执行、构造函数、析构函数。执行点可以选择before、after、around,分别表示在这些切入点的前面、后面或替换掉整个函数。
3、tpj表示thisJoinPoint,表示切入点本身。上面的例子由于使用around替换了整个执行过程,所以要执行原来的操作还需要调用tpj->proceed()。这里的around完成的功能可由一个before和一个after代替
4、切入点的匹配模式。切入点通过字符串来匹配要切入的操作,“%”字符表示匹配任意类型(或名字),在AspectJ中,这个字符是“*”,由于C++中“*”用来定义指针,所以在Aspect C++中用“%”;“...”用来匹配任意个参数。
编译:
首先运行ac++ -p <你的源文件所在目录> -d <输出文件目录> -I<附加头文件目录>,这一步会转换C++源文件和Aspect C++源文件。
如果在安装了VC,编译时可指定INCLUDE路径及_WIN32宏。
ac++ -p <你的源文件所在目录> -d <输出文件目录> -I<附加头文件目录> -I"C:\Program Files\Microsoft Visual Studio 8\VC\include" -D_WIN32
然后直接编译:
cl <源文件名>.cc
上面这个程序在处理前运行结果如下:
经Aspect C++处理后运行结果:
众所周知,C++没有丰富的动态类型信息,更没有动态生成类的功能(C++类型在编译后就基本上没有类型存在了),所以无法像java一样采用动态代理来实现AOP。
Aspect C++是C++的一个AOP实现,它使用了插入代码的方法。
一个典型的Aspect C++示例需要一个C++源文件(.cpp)、一个Aspect C++源文件(.ah),通过ac++编译器把C++源文件和Aspect C++源文件转换成混合的C++源文件(如果有头文件也会转换),最后通过普通的C++编译器编译出可执行文件。
下面是一个简单的示例:
1、C++源文件:
#include
<
stdio.h
>
class A {
public :
int a( int i, float b);
};
int A::a( int i, float b) {
printf( " inside A::a(%d, %f)\n " , i, b);
return i;
}
void b( char c, char * str) {
printf( " inside b(%c, %s)\n " , c, str);
}
int main() {
A a;
a.a( 4711 , 3.14 );
b( ' H ' , " ello World " );
return 0;
}
class A {
public :
int a( int i, float b);
};
int A::a( int i, float b) {
printf( " inside A::a(%d, %f)\n " , i, b);
return i;
}
void b( char c, char * str) {
printf( " inside b(%c, %s)\n " , c, str);
}
int main() {
A a;
a.a( 4711 , 3.14 );
b( ' H ' , " ello World " );
return 0;
}
2、Aspect C++源文件:
#include
<
stdio.h
>
aspect Action {
advice execution( " % A::%(
)
"
)
||
execution(
"
% b(
)
"
) : around() {
printf( " A: before(exec) %s\n " , JoinPoint::signature());
printf( " that : %p\n " , tjp -> that());
printf( " target: %p\n " ,tjp -> target());
tjp -> proceed();
printf( " A: after(exec) %s\n " , JoinPoint::signature());
}
advice call( " % A::%(
)
"
)
||
call(
"
% b(
)
"
) : around() {
printf( " A: before(call) %s\n " , JoinPoint::signature());
printf( " that : %p\n " , tjp -> that());
printf( " target: %p\n " ,tjp -> target());
tjp -> proceed();
printf( " A: after(call) %s\n " , JoinPoint::signature());
}
};
aspect ActionB {
advice execution( " % A::%(
)
"
)
||
execution(
"
% b(
)
"
) : around() {
printf( " B: before(exec) %s\n " , JoinPoint::signature());
printf( " that : %p\n " , tjp -> that());
printf( " target: %p\n " ,tjp -> target());
tjp -> proceed();
printf( " B: after(exec) %s\n " , JoinPoint::signature());
}
advice call( " % A::%(
)
"
)
||
call(
"
% b(
)
"
) : around() {
printf( " B: before(call) %s\n " , JoinPoint::signature());
printf( " that : %p\n " , tjp -> that());
printf( " target: %p\n " ,tjp -> target());
tjp -> proceed();
printf( " B: after(call) %s\n " , JoinPoint::signature());
}
};
aspect Action {
advice execution( " % A::%(
![dot.gif](/Images/dot.gif)
![dot.gif](/Images/dot.gif)
printf( " A: before(exec) %s\n " , JoinPoint::signature());
printf( " that : %p\n " , tjp -> that());
printf( " target: %p\n " ,tjp -> target());
tjp -> proceed();
printf( " A: after(exec) %s\n " , JoinPoint::signature());
}
advice call( " % A::%(
![dot.gif](/Images/dot.gif)
![dot.gif](/Images/dot.gif)
printf( " A: before(call) %s\n " , JoinPoint::signature());
printf( " that : %p\n " , tjp -> that());
printf( " target: %p\n " ,tjp -> target());
tjp -> proceed();
printf( " A: after(call) %s\n " , JoinPoint::signature());
}
};
aspect ActionB {
advice execution( " % A::%(
![dot.gif](/Images/dot.gif)
![dot.gif](/Images/dot.gif)
printf( " B: before(exec) %s\n " , JoinPoint::signature());
printf( " that : %p\n " , tjp -> that());
printf( " target: %p\n " ,tjp -> target());
tjp -> proceed();
printf( " B: after(exec) %s\n " , JoinPoint::signature());
}
advice call( " % A::%(
![dot.gif](/Images/dot.gif)
![dot.gif](/Images/dot.gif)
printf( " B: before(call) %s\n " , JoinPoint::signature());
printf( " that : %p\n " , tjp -> that());
printf( " target: %p\n " ,tjp -> target());
tjp -> proceed();
printf( " B: after(call) %s\n " , JoinPoint::signature());
}
};
简单说明一下:
1、“aspect Action”定义了一个“方面”,名字是“Action”,定义一个方面可以理解为“我关注程序的这个方面”。
2、“advice 切入点:位置”定义一个“处理方法”,在切入点的指定位置上执行代码。切入点可以选择call、execution、construction、destruction,分别表示调用、执行、构造函数、析构函数。执行点可以选择before、after、around,分别表示在这些切入点的前面、后面或替换掉整个函数。
3、tpj表示thisJoinPoint,表示切入点本身。上面的例子由于使用around替换了整个执行过程,所以要执行原来的操作还需要调用tpj->proceed()。这里的around完成的功能可由一个before和一个after代替
4、切入点的匹配模式。切入点通过字符串来匹配要切入的操作,“%”字符表示匹配任意类型(或名字),在AspectJ中,这个字符是“*”,由于C++中“*”用来定义指针,所以在Aspect C++中用“%”;“...”用来匹配任意个参数。
编译:
首先运行ac++ -p <你的源文件所在目录> -d <输出文件目录> -I<附加头文件目录>,这一步会转换C++源文件和Aspect C++源文件。
如果在安装了VC,编译时可指定INCLUDE路径及_WIN32宏。
ac++ -p <你的源文件所在目录> -d <输出文件目录> -I<附加头文件目录> -I"C:\Program Files\Microsoft Visual Studio 8\VC\include" -D_WIN32
然后直接编译:
cl <源文件名>.cc
上面这个程序在处理前运行结果如下:
F:\soft\ac\examples\Action
>
main
inside A::a( 4711 , 3.140000 )
inside b(H, ello World)
inside A::a( 4711 , 3.140000 )
inside b(H, ello World)
经Aspect C++处理后运行结果:
F:\soft\ac\examples\Action
-
out
>
main
A: before(call) int A::a( int , float )
that : 00000000
target: 0012FF73
B: before(call) int A::a( int , float )
that : 00000000
target: 0012FF73
A: before(exec) int A::a( int , float )
that : 0012FF73
target: 0012FF73
B: before(exec) int A::a( int , float )
that : 0012FF73
target: 0012FF73
inside A::a( 4711 , 3.140000 )
B: after(exec) int A::a( int , float )
A: after(exec) int A::a( int , float )
B: after(call) int A::a( int , float )
A: after(call) int A::a( int , float )
A: before(call) void b( char , char * )
that : 00000000
target: 00000000
B: before(call) void b( char , char * )
that : 00000000
target: 00000000
A: before(exec) void b( char , char * )
that : 00000000
target: 00000000
B: before(exec) void b( char , char * )
that : 00000000
target: 00000000
inside b(H, ello World)
B: after(exec) void b( char , char * )
A: after(exec) void b( char , char * )
B: after(call) void b( char , char * )
A: after(call) void b( char , char * )
A: before(call) int A::a( int , float )
that : 00000000
target: 0012FF73
B: before(call) int A::a( int , float )
that : 00000000
target: 0012FF73
A: before(exec) int A::a( int , float )
that : 0012FF73
target: 0012FF73
B: before(exec) int A::a( int , float )
that : 0012FF73
target: 0012FF73
inside A::a( 4711 , 3.140000 )
B: after(exec) int A::a( int , float )
A: after(exec) int A::a( int , float )
B: after(call) int A::a( int , float )
A: after(call) int A::a( int , float )
A: before(call) void b( char , char * )
that : 00000000
target: 00000000
B: before(call) void b( char , char * )
that : 00000000
target: 00000000
A: before(exec) void b( char , char * )
that : 00000000
target: 00000000
B: before(exec) void b( char , char * )
that : 00000000
target: 00000000
inside b(H, ello World)
B: after(exec) void b( char , char * )
A: after(exec) void b( char , char * )
B: after(call) void b( char , char * )
A: after(call) void b( char , char * )