文檔中心

TD開發平臺_基礎

04.簡單對象系統

华东15选5 www.wjnoc.com 當需要調用第三方提供的代碼庫并使用其中的對象時,存在兩個問題: 1.需要對方庫的頭文件,里面必須有對象的完整定義,這就導致調用者可以查閱對象內部的細節,并可能會修改對象的數據破壞對象內部的一致性 ;并且也違背了??櫸庾暗腦?。 2.對于相同的頭文件,不同的編譯器也可能產生不同的內存布局,并且對于函數的名字改編(函數重載),不同的編譯器采用的方案也可能不同。為了解決這兩個問題,引入了面向組件的編程技術和接口的概念。接口就是一組函數定義,并且被映射到對象的虛函數上(假定不同的編譯器對虛函數的實現都是相同的)。對象要實現一個或多個接口就是繼承相應的接口對象,這樣把函數定義和函數實現分開,并且開發人員看不到實現對象的內部數據。

在本章中只介紹如何使用已經有的對象類型。
對象的使用包括以下內容:

1)對象的生存期管理
void * TObjectCreate(T_ID type, TTable *in); /*創建一個對象*/
void TObjectDestroy(void *object); /*銷毀一個對象*/
void TObjectHold(void *object); /*增加對象的引用計數*/
void TObjectDrop(void *object); /*減少對象的引用計數*/
對象的創建是復雜的,因為不同類型的對象創建需要的參數不同,即使相同類型的對象也可能有多個構造函數(參數不同)。所以這里用 TTable來封裝創建的參數,這樣就可以用同一個函數來創建所有類型的對象。如果沒有初始化參數,TObjectCreate的參數 in傳NULL。例如要創建一個 button類型的對象,這種對象在創建時需要位置( w,y)、大?。╳,h)和顯示文字( text)等信息,創建代碼如下:
void * create_button_object (Tint x, Tint y, Tint w, Tint h, const char
*text)
{
    void *button_obj;
    TTable *arg_t;
    arg_t = TTableCreate();
    TTableAddInt(arg_t, T_STRING_ID(x), x);
    TTableAddInt(arg_t, T_STRING_ID(y), y);
    TTableAddInt(arg_t, T_STRING_ID(w), w);
    TTableAddInt(arg_t, T_STRING_ID(h), h);
    TTableAddString(arg_t, T_STRING_ID(text), text, -1);
    button_obj = TObjectCreate (T_STRING_ID(button), arg_t);
    TTableDestroy(arg_t);
    return button_obj;
}
再如有一個網絡下載文件的對象,這種對象在創建時需要下載的文件鏈接地址,創建
代碼如下:
void *create_download_object (const char *file_address)
{
    void *url_obj;
    TTable * in;
    in = TTableCreate();
    TTableAddString(in,T_STRING_ID(url),file_address,-1);
    url_obj=TObjectCreate(T_STRING_ID(url), in);
    TTableDestroy(in);
    return url_obj;
}
所有對象內部都有一個引用計數,被創建時引用計數為 1;TObjectHold函數會對引用計數加 1;TObjectDrop函數會對引用計數減 1,并且如果減 1后等于 0,就會自動銷毀該對象(即執行對象的析構函數并釋放內存)。
TObjectDestroy函數用于銷毀對象,它首先執行該對象的析構函數,然后對引用計數減 1,如果等于 0就釋放內存,否則不釋放內存。因為增加引用計數和減少引用計數必須成對出現,所以由 TObjectDrop來釋放內存(不會重復調用析構函數)。
2)對象的方法調用
不同類型的對象支持不同的調用接口函數,如圖形界面中的所有控件( button,window等)都支持一組操作函數(即控件接口),這些函數的形式都已經穩定下來不會改變,并且經常被調用,如:
void TwShow(void *obj); /*控件的顯示*/
void TwHide(void *obj); /*控件的隱藏*/
void TwResize(void *obj, Tint new_w, Tint new_h); /*控件改變大小*/
void TwMove(void *obj, Tint new_x, Tint new_y); /*控件移動位置*/
注意這里沒有提供一個通用的函數調用接口,比如 Tint TObjectCustomMethod(void *obj, T_ID method, TTable *arg)。
3)對象的事件機制
事件機制并不是面向對象語言本身提供的,如按鈕有點擊事件,開發人員并不知道什么時間發生點擊,但是希望點擊的時侯能夠通知開發人員程序(通知開發人員就是自動調用開發人員的事件處理函數),事件就像操作系統里的中斷,事件處理函數就像中斷處理函數,但是允許同一個事件有多個處理函數,多個處理函數的調用順序是不確定的。所以事件機制從本質上講是一種靈活的函數回調機制。
首先開發人員需要注冊事件,即告訴對象我對你的什么事件感興趣,以及我的事件處理函數:
typedef void (*TObjectEvent_Func)(void *obj, T_ID event, TTable *in,
void *arg, TExist *exist);
Tint TObjectAddEventHandler(void *object, T_ID event,
TObjectEvent_Func func, void *arg);

調用 TObjectAddEventHandler()注冊事件,參數 object指定對象,參數 event標識一個事件,參數 func就是事件處理函數(原型為 TObjectEvent_Func,它的參數 in封裝了事件的參數,arg就等于 TObjectAddEventHandler的參數 arg),參數 exist和多線程有關??梢遠醞桓齠韻蟮耐桓鍪錄⒉岫喔鍪錄硨?,但是:相同的 object、相同的 event、相同的 func、相同的 arg不能重復注冊。
然后就是觸發事件:
Tint TObjectEvent(void *object, T_ID event, TTable *in);
TObjectEvent()函數就是串行調用指定對象和事件的所有的事件處理函數,執行完畢后才返回。參數 object指定對象,參數 event指定要觸發的事件,參數 in封裝這次事件的參數。因為這個函數誰都可以調用,所以可以是對象內部的實現代碼在發生事件時調用,觸發自己的事件,也可以由開發人員調用,模擬觸發事件。
需要說明的是: 1、同一個對象的相同事件不能重復觸發; 2、不能在觸發事件的過程中再次注冊相同對象的這個事件。
最后可以調用 TObjectDeleteEventHandler()刪除注冊的事件:
Tint TObjectDeleteEventHandler(void *object, T_ID event,TObjectEvent_Func func, void *arg);

4)對象的命名
可以給對象設置一個名字,方便通過名字來獲取和管理對象,當然對象也可以沒有名字,只要有控件的指針就可以訪問該控件。
Tint TObjectSetName(void *obj, const char *name); //給控件設置一個名字
const char *TObjectGetName(void *obj); //得到控件的名字,沒有返回NULL
void *TObjectGetFromName(const char *name); //通過名字查找控件,返回控
注意:所有的對象都不能重名,否則TObjectSetName 將設置失敗。
{ganrao}