TList对象的缺点与改进

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

一、TList的问题

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

int __fastcall Add(void * Item);

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

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

 

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

 ButtonList->Add(Button2);             //

 ButtonList->Add( new TButton(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 = new TList;   

ButtonList->Add(Button1);

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

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

//引用对象

button->Caption = "I hope it's really a button";   

delete ButtonList;

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

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

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

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

    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;

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

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

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=0; j<nCount; j++)

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

delete ControlList;

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

二、改进方法

如果TList知道它所处理的对象,那么它的许多缺点就自动消除。基于此,在TList的基础上我们引进了一个新类TTypedList,它是从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)       

{       

}

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);

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

            delete Item;

        return nIndex;       

    }

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

};   

#endif

 

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

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

#include <vcl.h>

#pragma hdrstop

 

#include "Unit1.h"

#include "typedlist.h"

 

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

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

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

        : TForm(Owner)

{

}

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

 

void __fastcall TForm1::CreateButtons()

{

// Create a list of buttons.

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

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

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

    ButtonList->Add(new TButton(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;   

}   

delete ButtonList;

  }

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

void __fastcall TForm1::FormShow(TObject *Sender)

{

CreateButtons();

}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值