2.1 点切

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展示了代码片段的一些结合点以及它们如何关联的。

2.1 点切_第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是一个纯虚点切,必须在派生方向中重新定义来指向真正的点切表达式。

你可能感兴趣的:(2.1 点切)