程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 在C++中通過模板規避潛在錯誤

在C++中通過模板規避潛在錯誤

編輯:C++入門知識

、注:本文節選自我正在創作的第二本書《C++跨平台與框架開發》,其中一些措詞並未就博文進行調整,閱讀時請注意。
 
模板(template)為C++帶來了泛型編程的能力,但也帶來了使用難度。大體上,使用模板的三大動機分別是提高復用性、去除強制轉換和規避潛在錯誤。在此讓我們看一看規避錯誤的一個例子。

假設我們有圖 1所示的被簡化了的定時器管理模塊程序。從構造函數來看,它的三個參數分別指明了定時器的延時時間、回調函數和回調函數的參數,其中的回調函數是通過timer_callback_t類加以封裝的。當定時器到期時,它的fire()函數會被調用。間接地,fire()函數調用定時器所保存回調函數類對象的handle()函數。
1. 
2. class timer_callback_t
3. {
4.     virtual void handle (timer_t &_timer, timer_callback_arg_t *_p_arg) = 0;
5. };
6. 
7. class timer_t
8. {
9. public:
10.     timer_t (msecond_t _duration, timer_callback_t *_p_callback, 
11.         timer_callback_arg_t *_p_callback_arg);
12. 
13. private:
14.     void fire ()
15.     {
16.         p_callback_.handle (this, p_callback_arg_);
17.     }
18. 
19.     timer_callback_t *p_callback_;
20.     timer_callback_arg_t *p_callback_arg_;
21. };
圖1
 
圖 2示例了如何使用定時器。首先,得針對定時器的用途通過派生timer_callback_t類實現相應的回調函數類。接著,在創建定時器時需實例化回調函數類。圖中foo()和bar()函數分別示例了兩種實例化回調函數類的方法,前者采用的是定義靜態類變量,後者采用的是通過new進行動態分配。
1. class connect_timeout_callback_t: public timer_callback_t
2. {
3.     void handle (timer_t &_timer, timer_callback_arg_t *_p_arg)
4.     {
5.         // do something here
6.     }
7. };
8. 
9. void foo ()
10. {
11.     static connect_timeout_callback_t callback;
12.     timer_t *p_timer = new timer_t (100, &callback, 0);
13. }
14. 
15. void bar ()
16. {
17.     connect_timeout_callback_t *p_callback = new connect_timeout_callback_t ();
18.     timer_t *p_timer = new timer_t (100, p_callback, 0);
19. }
圖2
 
定時器模塊的實現使得在foo()和bar()函數中實例化回調函數類的方法需要注意一些點,否則容易犯錯。在foo()函數所使用的方法中,如果不小心忘記了將類變量定義成靜態的,會因為變量分配在棧上而最終導致程序出錯;在bar()函數中,如果忘記了將通過new分配獲得的內存通過delete釋放,則會產生內在洩漏。能否通過設計避免這些潛在的問題呢?

圖3是對定時器管理模塊采用模板重寫後的程序。其中最大的變化是timer_t類的構造函數省去了指定回調函數類實例,且回調函數類和回調函數參數成為了兩個模板類型。另一個變化是,fire()函數中通過定義靜態變量的方式實例化回調函數類。
1. template <typename T_CALLBACK, typename T_CALLBACK_ARG>
2.     class timer_callback_t
3. {
4.     virtual void handle (timer_t <T_CALLBACK, T_CALLBACK_ARG> &_timer,
5.         T_CALLBACK_ARG _arg) = 0;
6. };
7. 
8. template <typename T_CALLBACK, typename T_CALLBACK_ARG>
9.     class timer_t
10. {
11. public:
12.     timer_t (msecond_t _duration, T_CALLBACK_ARG _callback_arg);
13. 
14. private:
15.     void fire ()
16.     {
17.         static T_CALLBACK callback;
18.         callback.handle (*this, callback_arg_);
19.     }
20. 
21.     T_CALLBACK_ARG callback_arg_;
22. };
圖3
 
圖4示例說明了新實現下如何使用一個定時器。很顯然,我們通過模板將一些潛在問題通過內部化的方式給規避了。
1. class connect_timeout_callback_t:
2.     public timer_callback_t <connect_timeout_callback_t, void *>
3. {
4.     void handle (timer_t <connect_timeout_callback_t, void *> &_timer, void *_arg)
5.     {
6.         // do something here
7.     }
8. };
9. 
10. void foo ()
11. {
12.     timer_t <connect_timeout_callback_t, void *> *p_timer = new timer (100, 0);
13. }
圖4

 

 

摘自 李雲

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved