TList对象的缺点与改进
一、TList的问题
1、TList主要用来存储对象的指针,使用方便,但是这个类的主要缺点是缺乏安全性,因为它存储并维护的是空指针(void *),让我们看看它的Add方法的原型:
int __fastcall Add(void *Item);
C++编译器能正确地将任何类型的指针转换为void *型指针,因此,TList的Add方法能接受你传给它的任何一个指针。这其中就产出了一个问题,当你想维护TList中的对象指针列表时,你能肯定TList中的指针具有相同类型吗?例如:
TList *ButtonList = newTList;
以上代码能正确编译通过,从中我们能看出,TList能处理任何对象,它在接受任何一个对象时不做任何类型检查。当你要引用TList中的一个对象时,由于它是一个空指针,你必须将它转换为一个正确类型的指针,具体方法如下:
TList *ButtonList = newTList;
ButtonList->Add(Button1);
TButton *button =reinterpret_cast<TButton*>(ButtonList->Items[1]);
//引用对象
button->Caption = "I hope it'sreally abutton";
deleteButtonList;
在以上代码中,TList的Item数组返回一个空指针(void *),要引用其中的一个TButton型的指针,必须将其转换为TButton型,这种转换的前提条件是你能肯定TList的Item返回的指针原来指向一个TButton对象。也许有个认为用dynamic_cast
2、TList的另一个缺点是它不能自动删除其列表中的指针,要完全删除列表,必须遍历整个列表,将列表中的指针一个个删除。例如:
TList*ButtonList = newTList;
ButtonList->Add(newTButton(Handle));
…
…
int nCount =ButtonList->Count;
for (int j=0;j<nCount; j++)
deleteButtonList;
从表面上看,上述代码非常完美,但是深入一点,我们会发现一个缺点:删除列表中的某个指针时,该指针是一个空指针,而删除一个空指针与删除一个TButton型的指针是不同的,因为删除一个空指针不能自动执行一个对象的析构函数,也就不能执行析构函数中的内存释放与重新分配操作,从而会造成内存空洞。
为了能正确删除TList对象中的指针,必须将它们的类型进行转换,这样编译器才能正确调用类的析构函数。因为VCL中的所有析构函数都是虚函数,我们可以将列表中的所有转换为一个公共的基类,例如:
TList *ControlList = newTList;
ControlList->Add(newTButton(Handle));
ControlList->Add(newTComboBox(Handle));
int nCount =ControlList->Count;
deleteControlList;
若TList对象中的指针对象都是从TWinControl继承下来的,则上述代码工作正确,若某指针对象是从TDataSet继承下来的,则上述代码工作又有问题。
二、改进方法
如果TList知道它所处理的对象,那么它的许多缺点就自动消除。基于此,在TList的基础上我们引进了一个新类TTypedList,它是从TList继承下来的一个模板类,它在TList方法的基础上提供了强制类型检查,同时也提供了自动删除列表中的指针的一个方法。代码如下:
//--------------------------------------------------------------
#ifndefTTYPEDLIST_H
#defineTTYPEDLIST_H
#include<classes.hpp>
template<classT>
class TTypedList : publicTList
{
private:
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)
{
}
void __fastcall Delete(intIndex)
{
}
void __fastcallClear(void)
{
T* __fastcallFirst(void)
{
}
int __fastcall IndexOf(T*Item)
{
void __fastcall Insert(intIndex, T*Item)
{
}
T* __fastcallLast(void)
{
}
int __fastcall Remove(T*Item)
{
__property T* Items[intIndex] = {read=Get,write=Put};
};
#endif
在C++Builder4中建一个新的应用程序,主要代码如下:
#include<vcl.h>
#pragmahdrstop
#include"Unit1.h"
#include"typedlist.h"
//---------------------------------------------------------------------
#pragmapackage(smart_init)
#pragma resource"*.dfm"
TForm1*Form1;
//---------------------------------------------------------------------__fastcallTForm1::TForm1(TComponent* Owner)
{
}
//---------------------------------------------------------------------
void __fastcallTForm1::CreateButtons()
{
// Create a list ofbuttons.
TTypedList<TButton> *ButtonList = newTTypedList<TButton>(false);
ButtonList->Add(newTButton(this));
ButtonList->Add(newTButton(this));
for (int j=0;j<ButtonList->Count;j++)
{
}
deleteButtonList;
}
//-------------------------------------------------------------------------
void __fastcallTForm1::FormShow(TObject *Sender)
{
CreateButtons();
}
//-------------------------------------------------------------------------以上代码在C++ Builder5+Pwin2000Professional环境下中通过。