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; }