更多 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