TList对象的缺点与改进

TList对象的缺点与改进

C++Builder中,VCL库包含一个TList类,用于管理指针列表。然而,TList类含有许多缺点,其中最严重的缺点是TList缺乏类型的安全性及内存空间的自动释放。本文将探讨TList类的缺点,并提出改进方法。

一、TList的问题

1TList主要用来存储对象的指针,使用方便,但是这个类的主要缺点是缺乏安全性,因为它存储并维护的是空指针(void *),让我们看看它的Add方法的原型:

int __fastcall Add(void *Item);

C++编译器能正确地将任何类型的指针转换为void *型指针,因此,TListAdd方法能接受你传给它的任何一个指针。这其中就产出了一个问题,当你想维护TList中的对象指针列表时,你能肯定TList中的指针具有相同类型吗?例如:

TList *ButtonList = newTList         //create a list of buttons

 

 ButtonList->Add(Button1);             //add some buttons to the list

 ButtonList->Add(Button2);             //

 ButtonList->Add(newTButton(this));   // OK so far

 ButtonList->Add(Application);          //Application is not a button

 ButtonList->Add(Form1);              //neither is Form1

 ButtonList->Add((void*)534);   

 ButtonList->Add(Screen);

以上代码能正确编译通过,从中我们能看出,TList能处理任何对象,它在接受任何一个对象时不做任何类型检查。当你要引用TList中的一个对象时,由于它是一个空指针,你必须将它转换为一个正确类型的指针,具体方法如下:

TList *ButtonList = newTList  

ButtonList->Add(Button1);

 ……            // 生成一个对象指针列表

TButton *button =reinterpret_cast<TButton*>(ButtonList->Items[1]);

//引用对象

button->Caption = "I hope it'sreally abutton";   

deleteButtonList;

在以上代码中,TListItem数组返回一个空指针(void *),要引用其中的一个TButton型的指针,必须将其转换为TButton型,这种转换的前提条件是你能肯定TListItem返回的指针原来指向一个TButton对象。也许有个认为用dynamic_cast 操作符来完成这种转换,然而不幸的是由于空指针不含有任何类型信息,上述缺点仍然无法消除。

2TList的另一个缺点是它不能自动删除其列表中的指针,要完全删除列表,必须遍历整个列表,将列表中的指针一个个删除。例如:

  TList*ButtonList = newTList         // 生成一个对象列表

    ButtonList->Add(newTButton(Handle));   // 向列表中添加TButton对象

    ButtonList->Add(newTButton(Handle));

    ButtonList->Add(newTButton(Handle));

ButtonList->Add(newTButton(Handle));   

int nCount =ButtonList->Count;    //引用列表中对象的个数

for (int j=0;j<nCount; j++)

        deleteButtonList->Items[j];    // 删除指针

  deleteButtonList;

从表面上看,上述代码非常完美,但是深入一点,我们会发现一个缺点:删除列表中的某个指针时,该指针是一个空指针,而删除一个空指针与删除一个TButton型的指针是不同的,因为删除一个空指针不能自动执行一个对象的析构函数,也就不能执行析构函数中的内存释放与重新分配操作,从而会造成内存空洞。

为了能正确删除TList对象中的指针,必须将它们的类型进行转换,这样编译器才能正确调用类的析构函数。因为VCL中的所有析构函数都是虚函数,我们可以将列表中的所有转换为一个公共的基类,例如:

TList *ControlList = newTList  

ControlList->Add(newTButton(Handle));

    ControlList->Add(newTEdit(Handle));

ControlList->Add(newTComboBox(Handle));   

int nCount =ControlList->Count;

    for(int j=0; j<nCount; j++)

        deletereinterpret_cast<TWinControl*>(ControlList->Items[j]);

deleteControlList;

TList对象中的指针对象都是从TWinControl继承下来的,则上述代码工作正确,若某指针对象是从TDataSet继承下来的,则上述代码工作又有问题。

二、改进方法

如果TList知道它所处理的对象,那么它的许多缺点就自动消除。基于此,在TList的基础上我们引进了一个新类TTypedList,它是从TList继承下来的一个模板类,它在TList方法的基础上提供了强制类型检查,同时也提供了自动删除列表中的指针的一个方法。代码如下:

//--------------------------------------------------------------

#ifndefTTYPEDLIST_H   

#defineTTYPEDLIST_H

#include<classes.hpp>

template<classT>   

class TTypedList : publicTList   

{   

private:

        bool  bAutoDelete;   

protected:       

T* __fastcall Get(intIndex)

{           

return (T*)TList::Get(Index);       

 }

void __fastcall Put(intIndex, T*Item)       

{

TList::Put(Index,Item);       

    

public:

__fastcall TTypedList(boolbFreeObjects =false)         

:TList(),

bAutoDelete(bFreeObjects)       

{       

}

int __fastcall Add(T*Item)       

{           

    returnTList::Add(Item);

      

void __fastcall Delete(intIndex)       

{

        if(bAutoDelete)               

            deleteGet(Index);

        TList::Delete(Index);       

      

void __fastcallClear(void)

{           

    if(bAutoDelete)           

    {

            for(int j=0; j<Count;j++)                    

              deleteItems[j];

        }

        TList::Clear();       

    }

T* __fastcallFirst(void)       

{           

    return(T*)TList::First();

      

int __fastcall IndexOf(T*Item)       

{

        returnTList::IndexOf(Item);        

    }

void __fastcall Insert(intIndex, T*Item)       

{

        TList::Insert(Index,Item);       

      

T* __fastcallLast(void)

{           

    return(T*)TList::Last();       

}

int __fastcall Remove(T*Item)       

{

        intnIndex = TList::Remove(Item);

        if(bAutoDelete&& (nIndex !=-1))               

            deleteItem;

        returnnIndex;       

    }

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

};   

#endif

 

    最后根据改进的TTypedList类举个例了:

  在C++Builder4中建一个新的应用程序,主要代码如下:

#include<vcl.h>

#pragmahdrstop

 

#include"Unit1.h"

#include"typedlist.h"

 

//---------------------------------------------------------------------

#pragmapackage(smart_init)

#pragma resource"*.dfm"

TForm1*Form1;

//---------------------------------------------------------------------__fastcallTForm1::TForm1(TComponent* Owner)

        :TForm(Owner)

{

}

//---------------------------------------------------------------------

 

void __fastcallTForm1::CreateButtons()

{

// Create a list ofbuttons.

TTypedList<TButton> *ButtonList = newTTypedList<TButton>(false);

ButtonList->Add(newTButton(this));   

ButtonList->Add(newTButton(this));

    ButtonList->Add(newTButton(this));

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;   

  

deleteButtonList;

  }

//-------------------------------------------------------------------------

void __fastcallTForm1::FormShow(TObject *Sender)

{

CreateButtons();

}

//-------------------------------------------------------------------------以上代码在C++ Builder5+Pwin2000Professional环境下中通过。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值