AOP的核心思想是對橫切關注點進行模塊化。Aspect C++是針對C++的AOP擴展。
-
join point:運行aspects的代碼部分,可以使類、結構、聯合、對象、控制流
execution join point與可執行函數名關聯。純虛函數不可執行,因此可執行join point的advice代碼不能應用於純虛函數。但純虛函數的調用,即這類函數作爲call join point,是可以的。
call join point與兩個名字相關:源(調用者)名字和調用的目標函數(被調用者)的名字。由於同一個函數中會有很多函數調用,每個函數名可以被關聯到一系列的call join point。
construction join point爲當創建實例時。destruction join point對應於析構實例。 -
pointcut:是join point的集合。用來定義在什麼地方插入advice代碼,進行橫向切入。類似於C++中的變量,只不過帶個括號。定義格式: pointcut 變量名() = 標誌符( ||標誌符…… )
匹配表達式(name pointcut) "int C::%(...)" 匹配所有類C中返回值爲int的成員函數; "%List" 匹配任意以“List”爲結尾的類、結構、聯合或枚舉; "% printf(const char *, ...)" 匹配全局域中名字爲print、擁有至少一個const char *型形參、返回任意類型的函數; "const %& ...::%(...)" 匹配所有返回值爲const reference的函數; pointcut表達式 "%List" && !derived("Queue") 描述以List結尾、不派生自基類Queue的所有類; call("void draw()") && within("Shape") 描述所有對類Shape中void draw()方法的調用;
pointcut聲明 pointcut lists() = derived("List");
-
advice:定義橫向切入時加到pointcut的代碼。有一點像C中的函數,只不過這個函數自己指定了他運行的地方(pointcut)。當然加的代碼不侷限於函數,也可以是data。advice只能定義與aspect聲明中。定義函數的格式: advice pointcut名() : 函數返回值 advice類型名() { 代碼 }
advice execution("void login(...)") : before() { cout < < "Logging in." < < endl; }
pointcut表達式後的代碼段“:before()”表明,advice代碼再code join point到達前執行。
“:after()”同理。
“:around()”表示執行advice代碼,不執行code join point代碼。
這種情況下,如果需要執行code join point代碼,需要顯示的通過proceed()指明。
程序中的代碼沒有訪問advice代碼的權限。可以訪問上下文信息的advice聲明 pointcut new_user(const char *name) = execution("void login(...)") && args(name); advice new_user(name) : before(const char *name) { cout < < "User " < < name < < " is logging in." < < endl; }
-
aspect:類似於C++中的class,但aspect不僅包含data、function,還包含advice。aspect可以從class派生而來,反之不行。aspect的定義和class一樣,區別僅僅在於裏面包含advice的聲明或定義。
-
slices:slice是C++語言元素中定義一個範圍的段落。advice可利用slice擴展程序的靜態結構。例如,利用advice,class類型slice中的元素可被加到一個或多個目標類中。
slice class Chain { Chain *_next; public: Chain *next () const { return _next; } };
-
introduction:AspectC++支持的第二種advice是introduction。introduction用於擴展程序代碼和數據。
和普通advice聲明相同,introduction也以關鍵字advice打頭。如果advice後的pointcut是name pointcut,那麼“:”之後的slice聲明就被引入(introduce)到pointcut所規定類或aspects中。
使用引入的代碼和使用普通程序代碼一樣。
introduction中的advice代碼擁有join point處程序代碼的完全訪問權限,引入到class中的方法能夠訪問該class的私有成員。pointcut shapes() = "Circle" || "Polygon"; advice shapes() : slice class { bool m_shaded; void shaded(bool state) { m_shaded = state; } };
引入基類 advice "%Object" : slice class : public MemoryPool { virtual void release() = 0; }