如何让TList转让类型 做市安全

2014年3月 C++ Builder大版内专家分月排行榜第二2014年1月 C++ Builder大版内专家分月排行榜第二2013年12月 C++ Builder大版内专家分月排行榜第二2013年8月 C++ Builder大版内专家分月排行榜第二2013年7月 C++ Builder大版内专家分月排行榜第二2013年4月 Delphi大版内专家分月排行榜第二
2013年11月 C++ Builder大版内专家分月排行榜第三2013年9月 C++ Builder大版内专家分月排行榜第三2013年6月 C++ Builder大版内专家分月排行榜第三2013年3月 Delphi大版内专家分月排行榜第三
2014年3月 C++ Builder大版内专家分月排行榜第二2014年1月 C++ Builder大版内专家分月排行榜第二2013年12月 C++ Builder大版内专家分月排行榜第二2013年8月 C++ Builder大版内专家分月排行榜第二2013年7月 C++ Builder大版内专家分月排行榜第二2013年4月 Delphi大版内专家分月排行榜第二
2013年11月 C++ Builder大版内专家分月排行榜第三2013年9月 C++ Builder大版内专家分月排行榜第三2013年6月 C++ Builder大版内专家分月排行榜第三2013年3月 Delphi大版内专家分月排行榜第三
2013年8月 Delphi大版内专家分月排行榜第二2013年7月 Delphi大版内专家分月排行榜第二2013年6月 Delphi大版内专家分月排行榜第二2013年5月 Delphi大版内专家分月排行榜第二2013年3月 Delphi大版内专家分月排行榜第二
2013年2月 Delphi大版内专家分月排行榜第三
2013年8月 Delphi大版内专家分月排行榜第二2013年7月 Delphi大版内专家分月排行榜第二2013年6月 Delphi大版内专家分月排行榜第二2013年5月 Delphi大版内专家分月排行榜第二2013年3月 Delphi大版内专家分月排行榜第二
2013年2月 Delphi大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。         
您现在的位置:&&>&&>&&>&&>&&>&正文
如何让TList类型安全
来源:()  【】 
&&   在VCL中包含有一个TList类,相信很多朋友都使用过,它可以方便的维护对象指针,所以很多朋友都喜欢用它&& 来实现控件数组。不幸的是,这个TList类有一些问题,其中最重要就是缺乏类型安全的支持。&& 这篇文章介绍如何从TList派生一个新类来实现类型安全,并且能自动删除对象指针的方法。&& TList的问题所在&& 对于TList的方便性这里就不多说,我们来看一下,它到底存在什么问题,在Classes.hpp文件中,我们可以看到函数的原型是这样申明的&& int __fastcall Add(void * Item);&& 编译器可以把任何类型的指针转换为void*类型,这样add函数就可以接收任何类型的对象指针,这样问题就来了,如果你仅维护一种类型的指针也许还看不到问题的潜在性,下面我们以一个例子来说明它的问题所在。假设你想维护一个TButton指针,TList当然可以完成这样的工作但是他不会做任何类型检查确保你用add函数添加的一定是TButton*指针。&& TList *ButtonList = new TL&&& // 创建一个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 TL&& ButtonList-&Add(Button1);&& ButtonList-&Add(Button2);&& ButtonList-&Add(Application);&& TButton *button = reinterpret_cast&TButton *&(ButtonList-&Items);&& button-&Caption = "I hope it‘s really a button";&& delete ButtonL&& 相信你已经看到了问题的所在,当你需要取得指针引用的时候TList并不知道那是个什么类型的指针,所以你需要转换,但谁能保证ButtonList里一定是Button指针呢?你也许会马上想到使用dynamic_cast来进行转化。&& 不幸再次降临,dynamic_cast无法完成这样的工作,因为void类型的指针不包含任何类型信息,这意味着你不能使用这样的方法,编译器也不允许你这样做。&& dynamic_cast不能使用了,我们唯一的方法就是使用reinterpret_cast,不过这个操作符同以前c的强制类型转换没有任何区别,它总是不会失败,你可以把任何在任何指针间转换。这样你就没有办法知道List中是否真的是我们需要的Button指针。在上面的代码片断中,问题还不是非常严重,我们试图转换的指针是Application,当我们改变Caption属性的时候,最多把标题栏的Caption属性改了,可是如果我们试图转换的对象没有相应的属性呢?&& TList的第二个问题是,它自动删除对象指针的功能,当我们析构TList的时候,它并不能自动释放维护的指针数组的对象,很多时候我们需要用手工的方法来完成这样一件事情,下面的代码片断显示了如何释放他们&& TList *ButtonList = new TL&&&& // 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-&C&& for (int j=0; j&nC j++)&&& delete ButtonList-&Items[j];&& delete ButtonL&& (译注:上面的代码有问题,应该是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 TL&& ControlList-&Add(new TButton(Handle));&& ControlList-&Add(new TEdit(Handle));&& ControlList-&Add(new TComboBox(Handle));&& int nCount = ControlList-&C&& for (int j=nC j&=0; j--)&&& delete reinterpret_cast&TWinControl *&(ControlList-&Items[j]);&& delete ControlL&& 上面的代码可以安全的删除任何从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 bAutoD&& 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来释放内存& 1&&&
文章责编:gaoxiaoliang& 看了本文的网友还看了
?&&( 15:51:47)?&&( 14:16:20)?&&( 14:14:40)?&&( 14:13:00)?&&( 14:10:55)?&&( 14:02:35)
? ?   ? ?   ? ?   ? ?   ? ?
? ?   ? ?   ?
?   ? ?    ? ?   ? ?   ? ?   ? ?
? ?   ? ?
实用工具 |
| 大全 | 大全
     |
版权声明:如果网所转载内容不慎侵犯了您的权益,请与我们联系,我们将会及时处理。如转载本内容,请注明出处。
Copyright & 2004-
 网 All Rights Reserved 
中国科学院研究生院权威支持(北京) 电 话:010- 传 真:010-  从Delphi5开始VCL中增加了新的Contnrs单元,单元中定义了8个新的类,全部都是基于标准的TList类。
TList                       
  TList类实际上就是一个可以存储指针的容器类,提供了一系列的方法和属性来增加、删除、重排、定位、存取和排序容器中的类,它是基于数组的机制来实现的容器,比较类似于C++中的Vector和Java中的ArrayList。
  TList经常用来保存一组对象列表,基于数组实现的机制使得用下标存取容器中的对象非常快,但是随着容器的对象的增多,插入和删除对象速度直线下降,因此不适合频繁增加和删除对象的应用场景。
  下面是TList类的属性和方法说明:
Count: I  属性。返回列表中的项目数。
Items[Index: Integer]: P default  属性。通过以0为底的索引下标直接存取列表中的项目。
Add(Item: Pointer): I  函数。用来向列表中添加指针。
C  过程。清空列表中的项目。
Delete(Index: Integer);  过程。删除列表中对应索引的项目。
IndexOf(Item: Pointer):I  函数。返回指针在列表中的索引。
Remove(Item: Pointer):  函数。从列表中删除指针。
Capacity: Integer。  属性。可以用来获取或设定列表可以容纳的指针的数目。
Extract(Item: Pointer): P  函数。Extract类似于Remove可以将指针从列表中删除,不同的是返回被删除的指针。
Exchange(Index1, Index2: Integer);  过程。交换列表中的两个指针。
First: P  函数。返回链表中的第一个指针。
Last: P  函数。返回链表中的最后一个指针。
Move(CurIndex, NewIndex: Integer);  过程。将指针从当前位置移动到新的位置。
P  过程。从列表中删除所有nil的指针。
Sort(Compare: TListSortCompare);  过程。用来对链表中的项目进行排序,可以设定Compare参数为用户定制的排序函数。
TObjectList                   
  TObjectList类直接从TList类继承,可以作为对象的容器。TObjectList类定义如下:
TObjectList = class(TList)
constructor C
constructor Create(AOwnsObjects: Boolean);
function Add(AObject: TObject): I
function Remove(AObject: TObject): I
function IndexOf(AObject: TObject): I
function FindInstanceOf(AClass: TC AExact: Boolean=T
AStartAt:Integer=0):I
procedure Insert(Index: I AObject: TObject);
property OwnsObjects: B
property Items[Index: Integer]: TO default
  不同于TList类,TObjectList类的Add、Remove、IndexOf、Insert等方法都需要传递TObject对象作为参数,由于有了编译期的强类型检查,使得TObjectList比TList更适合保存对象。
  此外TObjectList对象有OwnsObjects属性。当设定为True(默认值),同TList类相同,TObjectList对象将销毁任何从列表中删除的对象。
  有了TObjectList类,我们就再也不用使用循环来释放对象了。这就避免了释放链表对象时,由于忘记释放链表中的对象而导致的内存泄漏。
  另外需要注意的是OwnsObjects属性不会影响到Extract方法,TObjectList的Extract方法行为类似于TList,知识从列表中移除对象引用,而不会销毁对象。
  TObjectList对象还提供了一个FindInstanceOf 函数,可以返回只有指定对象类型的对象在列表中的索引。如果AExtract参数为True,只有指定对象类型的对象实例会被定位,如果AExtract对象为False,AClass的子类实例也将被定为。AStartAt参数可以用来找到列表中的多个实例,只要每次调用FindInstanceOf函数时,将起始索引加1,就可以定位到下一个对象,之道FindInstanceOf 返回-1。下面是示例代码:
idx:= Object.FindInstanceOf(TMyObject, True, idx+1);
if idx&=0 then
until(idx&0);
TComponentList                 
  Contnrs单元中还定义了TCompontentList类,类定义如下
TComponentList = class(TObjectList)
function Add(AComponent: TComponent): I
function Remove(AComponent: TComponent): I
function IndexOf(AComponent: TComponent): I
procedure Insert(Index: I AComponent: TComponent);
property Items[Index: Integer]: TC
  注意TComponentList是从TObjectList类继承出来的,它的Add、Remove、IndexOf、Insert和Items方法调用都使用TComponent类型的参数而不再是TObject类型,因此适合作为TComponent对象的容器。
  TComponentList类还有一个特殊的特性,就是如果链表中的一个组件被释放的话,它将自动的从TComponentList链表中删除。这是利用TComponent的FreeNotification方法可以在组件被销毁时通知链表,这样链表就可以将对象引用从链表中删除的。
TClassList类                   
  Contnrs单元中还定义了TClassList类,类定义如下
TClassList = class(TList)
function GetItems(Index: Integer): TC
procedure SetItems(Index: I AClass: TClass);
function Add(aClass: TClass): I
function Remove(aClass: TClass): I
function IndexOf(aClass: TClass): I
procedure Insert(Index: I aClass: TClass);
property Items[Index: Integer]: TClass read GetItems write SetI
  不同于前面的两个类,这个类继承自TList,只是将Add、Remove、IndexOf和Items调用的参数从指针换成了TClass元类类型
阅读(...) 评论()
业精于勤而荒于嬉,行成于思而毁于随
十万小时的反复练习如何让TList类型安全_百度知道
如何让TList类型安全
我有更好的答案
高度复用性的,以及类型安全的。如果使用STL,TList的替代品是Vector,STL是轻便的,没有类型安全,没有自动删除机制,高弹性,改代码又那么麻烦,有没有更简单的方法?答案是STL建议你使用STL通过上面的代码论述,很多初学者可能会害怕
为您推荐:
其他类似问题
您可能关注的内容
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 转让类型 做市 的文章

 

随机推荐