C++之AOP

C++之AOP

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++源文件:
#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(
47113.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());
  }
};

簡單說明一下:
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(
47113.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(
47113.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 *)
轉自http://qiezi.javaeye.com/blog/26673

 

aspectc

http://www.cs.ubc.ca/labs/spl/projects/aspectc.html

http://sailhome.cs.queensu.ca/~bram/aspicere/index.html

aspectcpp

http://www.oschina.net/p/aspectcpp

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章