更多 C++ 惯用法/执行环绕指针
外观
提供一个智能指针对象,它在对对象上的每个函数调用之前和之后透明地执行操作,前提是执行的操作对于所有函数都是相同的。[1] 这可以被视为面向切面的编程 (AOP) 的一种特殊形式。
智能指针或装饰器的双重应用。
通常需要在类的每个成员函数调用之前和之后执行一个功能。例如,在多线程应用程序中,需要在修改数据结构之前加锁,并在之后解锁。在数据结构可视化应用程序中,可能希望在每次插入/删除操作之后查看数据结构的大小。
using namespace std;
class Visualizer {
std::vector <int> & vect;
public:
Visualizer (vector<int> &v) : vect(v) {}
void data_changed () {
std::cout << "Now size is: " << vect.size();
}
};
int main () // A data visualization application.
{
std::vector <int> vector;
Visualizer visu (vector);
//...
vector.push_back (10);
visu.data_changed ();
vector.push_back (20);
visu.data_changed ();
// Many more insert/remove calls here
// and corresponding calls to visualizer.
}
这种函数调用的重复是容易出错且乏味的。如果能够自动调用可视化器,那就太好了。可视化器也可以用于 std::list <int>。这种不是单个类的一部分而是跨越多个类的功能通常被称为方面。这个特殊的惯用法对于设计和实现简单的方面非常有用。
class VisualizableVector {
public:
class proxy {
public:
proxy (vector<int> *v) : vect (v) {
std::cout << "Before size is: " << vect->size ();
}
vector<int> * operator -> () {
return vect;
}
~proxy () {
std::cout << "After size is: " << vect->size ();
}
private:
vector <int> * vect;
};
VisualizableVector (vector<int> *v) : vect(v) {}
proxy operator -> () {
return proxy (vect);
}
private:
vector <int> * vect;
};
int main()
{
vector<int> vec;
VisualizableVector vecc(&vec);
//...
vecc->push_back(10); // Note use of -> operator instead of . operator
vecc->push_back(20);
}
可视化向量重载的 -> 运算符创建一个临时代理对象并返回它。代理对象的构造函数记录向量的尺寸。然后调用代理对象的重载 -> 运算符,它只是通过返回指向它的原始指针将调用转发给底层向量对象。在对向量的实际调用完成后,代理对象的析构函数再次记录尺寸。因此,可视化的记录是透明的,主函数免于杂乱。这种惯用法是执行环绕代理的特殊情况,执行环绕代理更通用和更强大。
如果我们明智地将这种惯用法与模板结合起来并连接重载的 -> 运算符,我们可以发挥它的真正威力。
template <class NextAspect, class Para>
class Aspect
{
protected:
Aspect (Para p): para_(p) {}
Para para_;
public:
NextAspect operator -> ()
{
return NextAspect (para_);
}
};
template <class NextAspect, class Para>
struct Visualizing : Aspect<NextAspect, Para>
{
public:
Visualizing (Para p)
: Aspect<NextAspect, Para> (p)
{
std::cout << "Before Visualization aspect" << std::endl;
}
~Visualizing ()
{
std::cout << "After Visualization aspect" << std::endl;
}
};
template <class NextAspect, class Para>
struct Locking : Aspect<NextAspect, Para>
{
public:
Locking (Para p)
: Aspect<NextAspect, Para> (p)
{
std::cout << "Before Lock aspect" << std::endl;
}
~Locking ()
{
std::cout << "After Lock aspect" << std::endl;
}
};
template <class NextAspect, class Para>
struct Logging : Aspect<NextAspect, Para>
{
public:
Logging (Para p)
: Aspect <NextAspect, Para> (p)
{
std::cout << "Before Log aspect" << std::endl;
}
~Logging ()
{
std::cout << "After Log aspect" << std::endl;
}
};
template <class Aspect, class Para>
class AspectWeaver
{
public:
AspectWeaver (Para p) : para_(p) {}
Aspect operator -> ()
{
return Aspect (para_);
}
private:
Para para_;
};
#define AW1(T,U) AspectWeaver<T<U, U>, U>
#define AW2(T,U,V) AspectWeaver<T<U<V, V>, V>, V>
#define AW3(T,U,V,X) AspectWeaver<T<U<V<X, X>, X>, X>, X>
int main()
{
vector<int> vec;
AW3(Visualizing, Locking, Logging, vector <int> *) X(&vec);
//...
X->push_back(10); // Note use of -> operator instead of . operator
X->push_back(20);
}
- ↑ 执行环绕序列 - Kevlin Henney