2.1 点切
AspectC++的方向以模块化的方式实现了横切关注点。出于这个考虑,AspectC++语言中最重要的元素是点切。点切描述了一系列结合点来决定什么情况下某一方向应该有作用。因此每个结合点既可以指代函数、属性、类型、变量或者结合点可访问的点,这样这一情况可以实例化事件来实现设计好的代码位置。根据不同的点切,他们将在编译时或者运行时被估算。
2.1.1 匹配表达式
AspectC++中有两种点切:代码点切和名称点切。名称点切描述了一系列(静态)已知程序入口,如类型、属性值、函数、变量和命名空间。所有的名称点切是基于匹配表达式的。匹配表达式可以被理解为搜索模式。这种搜索模式中,特殊字符“%”被解释成名称的通配符或标示符的一部分。特殊字符序列“...”匹配函数标示符的任意数量的参数,或者一个认证名称的任意数量的作用域。匹配表达式是带引号的字符串。
例:匹配表达式(名称点切)
"int C::%(...)"
匹配类C中所有返回int
的成员函数
"%List"
匹配任意以“List”结尾的类、结构体、共用体或枚举
"% printf(const char *, ...)"
匹配函数printf
(在全局作用域中定义)拥有至少一个const char *
类型的参数,并返回任意类型
"const %& ...::%(...)"
匹配返回常量对象引用的所有函数
匹配表达式根据定义的作用域、类型和名称选择程序入口。关于匹配表达式语义的详细介绍将在第三节中介绍。附录B中展示了定义正确句法的匹配表达式。
2.1.2 点切表达式
另一种点切,代码点切,描述了程序控制流中点集的交集。代码点切可以指代函数调用或执行的点。他们只能在名称点切的前提下创建,这是因为所有AspectC++支持的结合点需要至少一个定义的名称。它通过调用实现定义的点切函数实现,点切函数是以点切作为参数的点切表达式。within
(点切)就是这样一个点切函数的例子,它过滤了所有在给定点切的函数和类的结合点。
名称和代码点切可以在点切表达式中用代数操作符“&&”,“||”和“!”结合在一起。
例:点切表达式
"%List" && !derived("Queue")
描述了所有不是从类Queue
派生而来的以“List”结尾的类集
call("void draw()") && within("Shape")
描述了类Shape
中调用了函数draw
的方法集
2.1.3 结合点类型
除了AspectC++支持的两点类型的点切,还有两点类型的结合点。基于一小段代码片段可以清楚的分辨这两种类型的区别和联系。
class Shape;
void draw(Shape&);
namespace Circle {
typedef int PRECISION;
class S_Circle : public Shape {
PRECISION m_radius;
public:
...
void radius(PRECISION r) { m_radius = r; }
};
void draw(PRECISION r) {
S_Circle circle;
circle.radius(r);
draw(circle);
}
}
int main() {
Circle::draw(10);
return 0;
}
代码结合点用来组成代码点切,名称结点(如名称)用来组成名称切点。下面的图1展示了代码片段的一些结合点以及它们如何关联的。
图1 结合点它们的关系每一个执行结合点说可执行函数的名称相关联。纯虚函数并不能执行。因此,执行结合点的建议代码永远不会为这种函数触发。然而,这种函数的调用,如以此函数为目标的调用结合点,是完全有可能的。
每一个调用结合点通过两个名称关联:函数调用的原函数和目标函数的名称。因为统一函数可能存在多个函数调用,每一个函数名称可以和一堆调用结合点关联。一个构造结合点表示当是咧创建时类指定执行的指令序列。类似的,析构结合点表示对象析构。
2.1.4 点切声明
AspectC++通过点切声明来提供名称点切表达式的能力。这使得在不同的程序中复用点切表达式成为可能。在所有C++声明允许的地方都允许使用点切声明。因此常规的C++名称查询和继承规则同样适用于点切声明。
点切声明由关键词pointcut
引出。
例:点切声明
pointcut lists() = derived("List");
lists
现在可以在程序的任意地方使用,用来指代`derived("List")
而且,点切声明可以用来定义纯虚点切。这使得可复用虚方向成为可能,这将在2.4节讨论。除了在pointcut
后跟着virtual
关键词,点切表达式为“0”外,纯虚点切声明和普通的点切声明语法一样。
*例:纯虚点切声明
pointcut virtual methods() = 0;
methods
是一个纯虚点切,必须在派生方向中重新定义来指向真正的点切表达式。
网友评论