让TList类型安全

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

时间: 2024-08-17 18:21:07

让TList类型安全的相关文章

Java语言的接口与类型安全

安全 接口是实现构件可插入性的关键,可插入构件的关键在于存在一个公用的接口,以及每个构件实现了这个接口. 什么是接口? Java中的接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 接口的两种含义:一,Java接口,Java语言中存在的结构,有特定的语法和结构:二,一个类所具有的方法的特征集合,是一种逻辑上的抽象.前者叫做"Java接口",后者叫做"接口&qu

漫谈Java语言的接口与类型安全

安全 接口是实现构件可插入性的关键,可插入构件的关键在于存在一个公用的接口,以及每个构件实现了这个接口. 什么是接口? Java中的接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 接口的两种含义:一,Java接口,Java语言中存在的结构,有特定的语法和结构:二,一个类所具有的方法的特征集合,是一种逻辑上的抽象.前者叫做"Java接口",后者叫做"接口&qu

Delphi 2009泛型容器单元(Generics.Collections)[1]: TList

Delphi 2009 新增了泛型容器单元: Generics.Collections, 同时还有一个 Generics.Defaults 单元做支持. Generics.Collections 包含了以下实用类: TList<T> TQueue<T> TStack<T> TDictionary<TKey,TValue> TObjectList<T> TObjectQueue<T> TObjectStack<T> TObj

Swift语言指南(四) Swift语言的类型安全和类型推断

Swift是一门类型安全语言,类型安全语言需要代码里值的类型非常明确.如果你的代码中有部分值需要String类型,你就不能错误地传递Int. 鉴于Swift的类型安全,编译代码时,Swift会执行类型检查并将任何类型不匹配的地方标记为错误,使你在开发当中尽可能早的捕获并修正错误. 类型检查有助于你在操作不同值的类型时避免犯错.但这并不意味着你必须在声明每一个常量或变量时去检查类型,如果你不检查所需值的类型,Swift会执行类型推断来计算出相应地类型. 类型推断让编译器在编译代码时,根据你提供的值

类型安全的EventHandlerList

我们写一个类时,有时候会在同一个类上添加很多事件,事件很多的话,是不 容易管理的,.NET提供的EventHandlerList可以辅助多个事件的管理,但不方便 的地方是,它不是类型安全的,缺少类型安全,多少用起来担心会出错.经过我的 一番改造,可以将系统提供的EventHandlerList通过泛型提供类型安全的管理. 泛型类EventHandlerList.cs的实现如下: public sealed class EventHandlerList<T> : IDisposable { Li

TList

TList包含对象指针列表. 类关系 TObject Tlist用于存储和维护对象列表.TList引入属隆和方法以执行以下操作: (1)在列表中增加或删除对象. (2)在列表中重排对象. (3)在列表中定位和获得对象. (4)在列表中对对象进行排序. 属性列表 Capacity 标识TList对象维护的指针数组的大小. Count 表明在列表中使用的项的数量. Items 列出对象的引用. List 标识组成Items的指针数组. 方法列表 ~TList 删除与TList对象有关的内存. Add

JPA 2.0中的动态类型安全查询

自从 JPA 于 2006 年首次被引入之后,它就得到了 Java 开发社区的广泛支持.该规范的下一个主要更新 -- 2.0 版本 (JSR 317) -- 将在 2009 年年底完成.JPA 2.0 引入的关键特性之一就是 Criteria API,它为 Java 语言带来了一种独特的能力:开发一种 Java 编译器可以在运行时验证其正确性的查询.Criteria API 还提供一个能够在运行时动态地构建查询的机制. 本文将介绍 Criteria API 和与之密切相关的 元模型(metamo

为何我加入数据到TList之后读取出来是乱码,代码如下

问题描述 为何我加入数据到TList之后读取出来是乱码,代码如下 unit Unit1; interface uses Windows Messages SysUtils Variants Classes Graphics Controls Forms Dialogs StdCtrls; Type PL=^TL; TL=record str:string[20]; End; type TForm1 = class(TForm) Button_OpenFile: TButton; Memo_Tex

《Java核心技术 卷Ⅱ 高级特性(原书第10版)》一2.4.4 序列化单例和类型安全的枚举

2.4.4 序列化单例和类型安全的枚举 在序列化和反序列化时,如果目标对象是唯一的,那么你必须加倍当心,这通常会在实现单例和类型安全的枚举时发生. 如果你使用Java语言的enum结构,那么你就不必担心序列化,它能够正常工作.但是,假设你在维护遗留代码,其中包含下面这样的枚举类型: 这种风格在枚举被添加到Java语言中之前是很普遍的.注意,其构造器是私有的.因此,不可能创建出超出Orientation.HORIZONTAL和Orientation.VERTICAL之外的对象.特别是,你可以使用=