c++11 boost技術交流群:296561497,歡迎大家來交流技術。
c++中開源的AOP框架AspectC++需要單獨編譯才能將切面的代碼織入到核心邏輯代碼中,感覺使用起來不方便,不能滿足快速開發要求。我希望只要實現方法攔截即可,能織入before()和after()操作就行,不追求動態織入。思路是這樣的,通過一個包裝類,里面定義before()和after()方法,和->運算符重載方法,在重載操作函數中實現before()和after()操作。具體代碼如下:
BaseAspect
1 #include <boost/shared_ptr.hpp> 2 3 template <typename WrappedType, typename DerivedAspect> 4 class BaseAspect 5 { 6 protected: 7 WrappedType* m_wrappedPtr; //被織入的對象 8 9 //獲取派生的切面對象 10 DerivedAspect* GetDerived() 11 { 12 return static_cast<DerivedAspect*>(this); 13 } 14 15 //被織入對象的刪除器,用來自動觸發切面中的After方法 16 struct AfterWrapper 17 { 18 DerivedAspect* m_derived; 19 AfterWrapper(DerivedAspect* derived): m_derived(derived) {}; 20 void operator()(WrappedType* p) 21 { 22 m_derived->After(p); 23 } 24 }; 25 public: 26 explicit BaseAspect(WrappedType* p) : m_wrappedPtr(p) {}; 27 28 29 void Before(WrappedType* p) { 30 // Default does nothing 31 }; 32 33 void After(WrappedType* p) { 34 // Default does nothing 35 } 36 37 //重載指針運算符用來織入切面(Before和After) 38 boost::shared_ptr<WrappedType> operator->() 39 { 40 GetDerived()->Before(m_wrappedPtr); 41 return boost::shared_ptr<WrappedType>(m_wrappedPtr, AfterWrapper(GetDerived())); 42 } 43 }; 44 45 //織入切面的工廠函數, 返回包含被織入對象的切面 46 template <template <typename> class Aspect, typename WrappedType> 47 Aspect<WrappedType> MakeAspect(WrappedType* p) 48 { 49 return Aspect<WrappedType>(p); 50 }
BaseAspect為切面的基類,提供了Before()和After()方法,供派生的切面實現;
下面看看具體的切面實現:一個實現對函數運行時間的統計,一個實現日志功能。
TimeElapsedAspect
1 #include <iostream> 2 #include <boost/chrono/chrono.hpp> 3 #include <boost/chrono/system_clocks.hpp> 4 5 template<typename WrappedType> 6 class TimeElapsedAspect : public BaseAspect< WrappedType, TimeElapsedAspect<WrappedType> > 7 { 8 typedef BaseAspect<WrappedType, TimeElapsedAspect<WrappedType> > BaseAspect; 9 typedef boost::chrono::time_point<boost::chrono::system_clock, boost::chrono::duration<double> > time_point; 10 11 time_point m_tmBegin; 12 public: 13 TimeElapsedAspect(WrappedType* p): BaseAspect(p) {} 14 15 16 void Before(WrappedType* p) 17 { 18 m_tmBegin = boost::chrono::system_clock::now(); 19 } 20 21 void After(WrappedType* p) 22 { 23 time_point end = boost::chrono::system_clock::now(); 24 25 std::cout << "Time: " << (end-m_tmBegin).count() << std::endl; 26 } 27 };
TimeElapsedAspect切面實現對函數運行時間統計。
LoggingAspect
1 template <typename WrappedType> 2 class LoggingAspect : public BaseAspect<WrappedType, LoggingAspect<WrappedType> > 3 { 4 typedef BaseAspect<WrappedType, LoggingAspect<WrappedType> > BaseAspect; 5 public: 6 LoggingAspect(WrappedType* p): BaseAspect(p) {} 7 8 void Before(WrappedType* p) 9 { 10 std::cout << "entering" << std::endl; 11 } 12 13 void After(WrappedType* p) 14 { 15 std::cout << "exiting" << std::endl; 16 } 17 18 };
LoggingAspect實現日志記錄
現在來看看測試代碼
TestAop
class IX { public: IX(){} virtual ~IX(){} virtual void g()=0; private: }; class X : public IX { public: void g() { std::cout << "it is a test" << std::endl; } }; void TestAop() { boost::shared_ptr<IX> p(new X()); MakeAspect<TimeElapsedAspect>(p.get())->g(); MakeAspect<LoggingAspect>(p.get())->g(); }
測試結果:

總結:
這個簡單的AOP實現,可以實現對類的方法進行攔截,具體切面自由定制,不過還有個地方不太完善,還不支持切面的組合,這個可以用TypeList去實現。
