亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

讓TList類型安全

2019-11-17 05:22:20
字體:
來源:轉載
供稿:網友

  在VCL中包含有一個TList類,相信很多朋友都使用過,它可以方便的維護對象指針,所以很多朋友都喜歡用它

來實現控件數組。不幸的是,這個TList類有一些問題,其中最重要就是缺乏類型安全的支持。

這篇文章介紹如何從TList派生一個新類來實現類型安全,并且能自動刪除對象指針的方法。

TList的問題所在

對于TList的方便性這里就不多說,我們來看一下,它到底存在什么問題,在Classes.hpp文件中,我們可以看到函數的原型是這樣申明的:

int __fastcall Add(void * Item);

編譯器可以把任何類型的指針轉換為void*類型,這樣add函數就可以接收任何類型的對象指針,這樣問題就來了,假如你僅維護一種類型的指針也許還看不到問題的潛在性,下面我們以一個例子來說明它的問題所在。假設你想維護一個TButton指針,TList當然可以完成這樣的工作但是他不會做任何類型檢查確保你用add函數添加的一定是TButton*指針。

TList *ButtonList = new TList;        // 創建一個button list

ButtonList->Add(Button1);             // 添加對象指針
ButtonList->Add(Button2);             //
ButtonList->Add( new TButton(this));  // OK so far

ButtonList->Add(application);         // Application不是button
ButtonList->Add(Form1);               // Form1也不是
ButtonList->Add((void *)534);
ButtonList->Add(Screen);

上面的代碼可以通過編譯運行,因為TList可以接收任何類型的指針。

當你試圖引用指針的時候,真正的問題就來了:

TList *ButtonList = new TList;
ButtonList->Add(Button1);
ButtonList->Add(Button2);
ButtonList->Add(Application);

TButton *button = reinterPRet_cast<TButton *>(ButtonList->Items[2]);
button->Caption = "I hope it's really a button";

delete ButtonList;

相信你已經看到了問題的所在,當你需要取得指針引用的時候TList并不知道那是個什么類型的指針,所以你需要轉換,但誰能保證ButtonList里一定是Button指針呢?你也許會馬上想到使用dynamic_cast來進行轉化。

不幸再次降臨,dynamic_cast無法完成這樣的工作,因為void類型的指針不包含任何類型信息,這意味著你不能使用這樣的方法,編譯器也不答應你這樣做。

dynamic_cast不能使用了,我們唯一的方法就是使用reinterpret_cast,不過這個操作符同以前c的強制類型轉換沒有任何區別,它總是不會失敗,你可以把任何在任何指針間轉換。這樣你就沒有辦法知道List中是否真的是我們需要的Button指針。在上面的代碼片斷中,問題還不是非常嚴重,我們試圖轉換的指針是Application,當我們改變Caption屬性的時候,最多把標題欄的Caption屬性改了,可是假如我們試圖轉換的對象沒有相應的屬性呢?

TList的第二個問題是,它自動刪除對象指針的功能,當我們析構TList的時候,它并不能自動釋放維護的指針數組的對象,很多時候我們需要用手工的方法來完成這樣一件事情,下面的代碼片斷顯示了如何釋放他們:

TList *ButtonList = new TList;          // create a list of buttons

ButtonList->Add(new TButton(Handle));   // add some buttons to the list
ButtonList->Add(new TButton(Handle));
ButtonList->Add(new TButton(Handle));
ButtonList->Add(new TButton(Handle));

...
...

int nCount = ButtonList->Count;
for (int j=0; j<nCount; j++)
    delete ButtonList->Items[j];

delete ButtonList;

(譯注:上面的代碼有問題,應該是for(int j=nCount-1;j>=0;j--),及要反過來循環,否則可能出現AV)

表面上看來,上面的代碼能很好的工作,但是假如你深入思考就會發現潛在的問題。Items[j]返回的是一個void指針,這樣delete語句將會刪除void指針,但是刪除void指針與刪除TButton指針有很大的不同,刪除void指針并不會調用對象的析構器,這樣存在于析構器中的釋放內存的語句就沒有機會執行,這樣將造成內出泄漏。

完了能完全的刪除對象指針,你必須讓編譯器知道是什么類,才能調用相應的析構器。好在VCL的析構器都是虛擬的,你可以通過轉換為基類來安全的刪除派生類。比如假如你的List里包含了Button和ComboBox,有可以把他們轉換為TComponent、TControl、TWinControl來安全的刪除他們,示例代碼如下:

TList *ControlList = new TList;

ControlList->Add(new TButton(Handle));
ControlList->Add(new TEdit(Handle));
ControlList->Add(new TComboBox(Handle));

int nCount = ControlList->Count;
for (int j=nCount; j>=0; j--)
    delete reinterpret_cast<TWinControl *>(ControlList->Items[j]);

delete ControlList;

上面的代碼可以安全的刪除任何從TwinControl派生的子類,但是假如是TDatset呢?TDataSet并不是從TWinControl繼續的,這樣delete將調用TWinControl的析構器,這同樣可能造成運行時的錯誤。

改進TList

通過上面的論述,我們已經大概了解了TList需要如何改進。假如TList知道它處理的對象的類型,大多數的問題就解決了。下面的代碼就是為了這個目標來寫的:

#ifndef TTYPEDLIST_H
#define TTYPEDLIST_H

#include <classes.hpp>

template <class T>
class TTypedList : public TList
{
private:
    bool bAutoDelete;
protected:
    T* __fastcall Get(int Index)
    {
        return (T*) TList::Get(Index);
    }

    void __fastcall Put(int Index, T* Item)
    {
        TList::Put(Index,Item);
    }

public:
    __fastcall TTypedList(bool bFreeObjects = false)
      :TList(),
       bAutoDelete(bFreeObjects)
    {
    }

    // 注重:沒有析構器,直接調用Delete來釋放內存
    //       而且Clean時虛擬的,你知道怎么做了?

    int __fastcall Add(T* Item)
    {
        return TList::Add(Item);
    }

    void __fastcall Delete(int Index)
    {
        if(bAutoDelete)
            delete Get(Index);
        TList::Delete(Index);
    }

    void __fastcall Clear(void)
    {
        if(bAutoDelete)
        {
            for (int j=0; j<Count; j++)
                delete Items[j]; //(譯注:這行代碼同樣存在上面提到的問題)
        }
        TList::Clear();
    }

    T* __fastcall First(void)
    {
        return (T*)TList::First();
    }

    int __fastcall IndexOf(T* Item)
    {
        return TList::IndexOf(Item);
    }

    void __fastcall Insert(int Index, T* Item)
    {
        TList::Insert(Index,Item);
    }

    T* __fastcall Last(void)
    {
        return (T*) TList::Last();
    }

    int __fastcall Remove(T* Item)
    {
        int nIndex = TList::Remove(Item);
        // 假如bAutoDelete is true,我們將自動刪除item
        if(bAutoDelete && (nIndex != -1))
            delete Item;
        return nIndex;
    }

    __property T* Items[int Index] = {read=Get, write=Put};
};

#endif



實例代碼
//----------------------------------------------------------------------------
// 示例代碼1

#incude "typedlist.h"

void __fastcall TForm1::CreateButtons()
{
    // false,不自動刪除
    TTypedList <TButton> *ButtonList = new TTypedList <TButton>(false);

    ButtonList->Add(new TButton(this));
    ButtonList->Add(new TButton(this));
    ButtonList->Add(new TButton(this));

    // ButtonList->Add(Application);  <<-- 無法通過編譯

    for (int j=0; j<ButtonList->Count; j++)
    {
        ButtonList->Items[j]->Caption = "Button" + IntToStr(j);
        ButtonList->Items[j]->Left    = 250;
        ButtonList->Items[j]->Top     = 50 + j*25;
        ButtonList->Items[j]->Parent  = this;
    }

    delete ButtonList;
}

//----------------------------------------------------------------------------
// 實例代碼2

#incude "typedlist.h"

void __fastcall TForm1::CreateButtons()
{
    typedef TTypedList <TButton> TButtonList;

    TButtonList *ButtonList = new TButtonList(true);
    ButtonList->Add(new TButton(this));
    ...
    delete ButtonList;
}

//----------------------------------------------------------------------------
// Code Example 3: A list of tables and queries

#incude "typedlist.h"

void __fastcall TForm1::OpenDataSets()
{
    typedef TTypedList <TDataSet> TDataSetList;

    TDataSetList *list = new TDataSetList(false);
    list->Add(Table1);
    list->Add(Table2);
    list->Add(Table3);
    list->Add(Query1);

    for (int j=0; j<list->Count; j++)
        list->Items[j]->Active = true;

    delete list;
}

通過使用模板技術,我們把問題消滅在了編譯時期,而且也提供了自動刪除的機制,又由于上面的代碼使用了內聯技術(inline),所以也沒有犧牲代碼的效率。

建議你使用STL

通過上面的代碼論述,很多初學者可能會害怕,沒有類型安全,沒有自動刪除機制,改代碼又那么麻煩,有沒有更簡單的方法?答案是STL,STL是輕便的,高彈性,高度復用性的,以及類型安全的。假如使用STL,TList的替代品是Vector。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国a精品视频大全| 91久久国产婷婷一区二区| 亚洲mm色国产网站| 欧美精品一区二区免费| 亚洲欧美日韩中文在线制服| 亚洲国产91精品在线观看| 亚洲午夜国产成人av电影男同| 日韩av最新在线| 亚洲精品mp4| 亚洲最大在线视频| 宅男66日本亚洲欧美视频| 自拍偷拍亚洲区| 亚州精品天堂中文字幕| 久久精品91久久香蕉加勒比| 久久久久久久久久久人体| 国产视频精品久久久| 不卡av在线播放| 久久精品国产久精国产一老狼| 国产精品综合网站| 欧洲成人免费视频| 国产中文字幕亚洲| 亚洲无限av看| 日韩视频永久免费观看| 亚洲精品第一页| 尤物精品国产第一福利三区| 成人在线播放av| 国内精品美女av在线播放| 懂色av影视一区二区三区| 高清在线视频日韩欧美| 久久精品国亚洲| 69久久夜色精品国产69乱青草| 亚洲国产精品成人va在线观看| 国产91精品久久久久| 国产91精品高潮白浆喷水| 久久久久久久久爱| 亚洲人成网站777色婷婷| 国产精品对白刺激| 亚洲无亚洲人成网站77777| 一区二区三区动漫| 国产精品美女久久久久久免费| 国产精品视频自在线| 欧美另类在线播放| 91久久在线视频| 欧美肥臀大乳一区二区免费视频| 欧美一区二区三区免费观看| 国产精品久久久久9999| 国内精品久久久久影院 日本资源| 亚洲xxxx3d| 亚洲va电影大全| 亚洲国产精品成人av| 国产一区二区在线播放| 91国产视频在线播放| 国产精品电影观看| 日韩国产精品一区| 日本高清视频一区| 国产一区玩具在线观看| 亚洲精品欧美日韩专区| 国产91精品高潮白浆喷水| 亚洲最大激情中文字幕| 国产精品va在线播放我和闺蜜| 精品一区二区三区四区| 亚洲午夜小视频| 成人福利网站在线观看11| 亲爱的老师9免费观看全集电视剧| 国产精品视频一区二区三区四| 日韩在线观看免费高清完整版| 亚洲自拍中文字幕| 国产v综合v亚洲欧美久久| 欧美成人精品在线| 欧美中文字幕精品| 亚洲丝袜一区在线| 国语自产偷拍精品视频偷| 欧美日韩在线免费观看| 亚洲人成在线一二| 98精品国产高清在线xxxx天堂| 久久久久久久久久久av| 91在线国产电影| 欧美成人精品在线观看| 亚洲第一国产精品| 欧美黑人一级爽快片淫片高清| 亚洲深夜福利视频| 91视频国产高清| 亚洲xxxx3d| 亚洲免费一级电影| 欧美黑人巨大精品一区二区| 国产精品夜间视频香蕉| 亚洲天堂一区二区三区| 精品视频在线导航| 亚洲国产日韩一区| 国产欧美韩国高清| 欧美一级在线播放| 日本精品在线视频| 欧美自拍大量在线观看| 亚洲专区中文字幕| 日韩av最新在线观看| 精品电影在线观看| 色婷婷综合久久久久中文字幕1| 久久99精品国产99久久6尤物| 亚洲一区亚洲二区亚洲三区| 成人黄色影片在线| 欧美日韩第一页| 国产视频观看一区| 欧美激情综合色综合啪啪五月| 国产日韩在线亚洲字幕中文| 精品国产91久久久久久老师| 红桃视频成人在线观看| 影音先锋欧美精品| 伊人亚洲福利一区二区三区| 欧美另类暴力丝袜| 午夜精品一区二区三区在线播放| 日韩av电影中文字幕| 欧美成人午夜激情| 国产欧洲精品视频| 亚洲男人天堂视频| 国产成人鲁鲁免费视频a| 精品久久久国产精品999| 亚洲男人的天堂在线播放| 日韩一区二区三区在线播放| 91精品啪在线观看麻豆免费| 欧美日韩午夜视频在线观看| 久久伊人色综合| 精品福利在线观看| yw.139尤物在线精品视频| 欧美大学生性色视频| 在线精品播放av| 中文字幕在线日韩| 91精品久久久久久久久不口人| 久久亚洲精品一区| 5278欧美一区二区三区| 久久91亚洲精品中文字幕| 91嫩草在线视频| 久久国产精品久久久久久久久久| 6080yy精品一区二区三区| 91a在线视频| 日本高清+成人网在线观看| 亚洲国产中文字幕在线观看| 久久久亚洲欧洲日产国码aⅴ| 国产精品久久久久久中文字| 国产精品精品一区二区三区午夜版| 国产精品黄页免费高清在线观看| 深夜福利亚洲导航| 国产日产久久高清欧美一区| 亚洲伊人一本大道中文字幕| 91欧美精品午夜性色福利在线| 国产成人精品av| 91香蕉嫩草神马影院在线观看| 伊人亚洲福利一区二区三区| 国产成人在线精品| 不卡av日日日| 超碰精品一区二区三区乱码| 国产日韩欧美在线观看| 91在线直播亚洲| 国产精自产拍久久久久久蜜| 成人97在线观看视频| 45www国产精品网站| 亚洲男人天堂2023| 亚洲黄色成人网| 亚洲女同精品视频| 国产99久久精品一区二区 夜夜躁日日躁| 91国在线精品国内播放| 国产一区二区三区免费视频| 国产精品久久久久免费a∨| 91视频国产精品| 在线观看国产精品91|