当前位置:文档之家› Delphi中的容器类_陈省

Delphi中的容器类_陈省

Delphi中的容器类_陈省
Delphi中的容器类_陈省

Delphi中的容器类

作者陈省

从Delphi 5开始VCL中增加了一个新的Contnrs单元,单元中定义了8个新的类,全部都是基于标准的TList 类。

TList 类

TList 类实际上就是一个可以存储指针的容器类,提供了一系列的方法和属性来添加,删除,重排,定位,存取和排序容器中的类,它是基于数组的机制来实现的容器,比较类似于C++中的Vector和Java中的ArrayList,TList 经常用来保存一组对象列表,基于数组实现的机制使得用下标存取容器中的对象非常快,但是随着容器中的对象的增多,插入和删除对象速度会直线下降,因此不适合频繁添加和删除对象的应用场景。下面是TList类的属性和方法说明:

属性

描述

Count: Integer;

返回列表中的项目数

Items[Index: Integer]: Pointer; default

通过以0为底的索引下标直接存取列表中的项目

方法

类型

描述

Add(Item: Pointer): Integer;

函数

用来向列表中添加指针

Clear;

过程

清空列表中的项目

Delete(Index: Integer);

过程

删除列表中对应索引的项目

IndexOf(Item: Pointer): Integer;

函数

返回指针在列表中的索引

Insert(Index: Integer; Item: Pointer);

过程

将一个项目插入到列表中的指定位置

Remove(Item: Pointer): Integer;

函数

从列表中删除指针

名称

类型

描述

Capacity: Integer;

property

可以用来获取或设定列表可以容纳的指针数目

Extract(Item: Pointer): Pointer;

function

Extract 类似于Remove 可以将指针从列表中删除,不同的是返回被删除的指针。

Exchange(Index1, Index2: Integer);

procedure

交换列表中两个指针

First: Pointer;

function

返回链表中的第一个指针

Last: Pointer;

function

返回链表中最后一个指针

Move(CurIndex NewIndex: Integer);

procedure

将指针从当前位置移动到新的位置

Pack;

procedure

从列表中删除所有nil指针

Sort(Compare: TListSortCompare);

procedure

用来对链表中的项目进行排序,可以设定Compare参数为用户定制的排序函数

TObjectList 类

TObjectList 类直接从TList 类继承,可以作为对象的容器。TObjectList类定义如下:

TObjectList = class(TList)

...

public

constructor Create; overload;

constructor Create(AOwnsObjects: Boolean); overload;

function Add(AObject: TObject): Integer;

function Remove(AObject: TObject): Integer;

function IndexOf(AObject: TObject): Integer;

function FindInstanceOf(AClass: TClass;

AExact: Boolean = True; AStartAt: Integer = 0):

Integer;

procedure Insert(Index: Integer; AObject: TObject);

property OwnsObjects: Boolean;

property Items[Index: Integer]: TObject; default;

end;

不同于TList类,TObjectList类的Add, Remove, IndexOf, Insert等方法都需要传递TObject对象作为参数,由于有了编译期的强类型检查,使得TObjectList比TList更适合保存对象。此外TObjectList对象有OwnsObjects属性。当设定为True (默认值),同TList类不同,TObjectList对象将销毁任何从列表中删除的对象。无论是调用Delete, Remove, Clear 方法,还是释放TObjectList对象,都将销毁列表中的对象。有了TObjectList类,我们就再也不用使用循环来释放了对象。这就避免了释放链表对象时,由于忘记释放链表中的对象而导致的内存泄漏。另外要注意的是OwnsObjects属性不会影响到Extract方法,TObjectList的Extract方法行为类似于TList,只是从列表中移除对象引用,而不会销毁对象。

TObjectList 对象还提供了一个FindInstanceOf 函数,可以返回只有指定对象类型的对象实例在列表中的索引。如果AExact 参数为True,只有指定对象类型的对象实例会被定位,如果AExact 对象为False,AClass 的子类实例也将被定位。AStartAt 参数可以用来找到列表中的多个实例,只要每次调用FindInstanceOf 函数时,将起始索引加1,就可以定位到下一个对象,直到FindInstanceOf 返回-1。下面是代码示意:

var

idx: Integer;

begin

idx := -1;

repeat

idx := ObjList.FindInstanceOf(TMyObject, True, idx+1);

if idx >= 0 then

...

until(idx < 0);

end;

TComponentList 类

Contnrs单元中还定义了TComponentList 类,类定义如下:

TComponentList = class(TObjectList)

...

public

function Add(AComponent: TComponent): Integer;

function Remove(AComponent: TComponent): Integer;

function IndexOf(AComponent: TComponent): Integer;

procedure Insert(Index: Integer; AComponent: TComponent);

property Items[Index: Integer]: TComponent; default;

end;

注意TComponentList 是从TObjectList类继承出来的,它的Add, Remove, IndexOf, Insert和Items 方法调用都使用TComponent 类型的参数而不再是TObject类型,因此适合作为TComponent对象的容器。TComponentList 类还有一个特殊的特性,就是如果链表中的一个组件被释放的话,它将被自动的从TComponentList 链表中删除。这是利用TComponent的FreeNotification方法可以在组件被销毁时通知链表,这样链表就可以将对象引用从链表中删除的。

TClassList 类

Contnrs单元中还定义了TClassList类,类定义如下:

TClassList = class(TList)

protected

function GetItems(Index: Integer): TClass;

procedure SetItems(Index: Integer; AClass: TClass);

public

function Add(aClass: TClass): Integer;

function Remove(aClass: TClass): Integer;

function IndexOf(aClass: TClass): Integer;

procedure Insert(Index: Integer; aClass: TClass);

property Items[Index: Integer]: TClass

read GetItems write SetItems; default;

end;

不同于前面两个类,这个类继承于TList的类只是将Add, Remove, IndexOf, Insert和Items 调用的参数从指针换成了TClass元类类型。

TOrderedList, TStack和TQueue 类

Contnrs单元还定义了其它三个类:TOrderedList, TStack和TQueue,类型定义如下:

TOrderedList = class(TObject)

private

FList: TList;

protected

procedure PushItem(AItem: Pointer); virtual; abstract;

...

public

function Count: Integer;

function AtLeast(ACount: Integer): Boolean;

procedure Push(AItem: Pointer);

function Pop: Pointer;

function Peek: Pointer;

end;

TStack = class(TOrderedList)

protected

procedure PushItem(AItem: Pointer); override;

end;

TQueue = class(TOrderedList)

protected

procedure PushItem(AItem: Pointer); override;

end;

要注意虽然TOrderedList 并不是从TList继承的,但是它在内部的实现时,使用了TList来储存指针。另外注意TOrderedList类的PushItem 过程是一个抽象过程,所以我们无法实例化TOrderedList 类,而应该从TOrderedList继承新的类,并实现抽象的PushItem方法。TStack 和TQueue 正是实现了PushItem抽象方法的类,我们可以实例化TStack 和TQueue类作为后进先出的堆栈(LIFO)和先进先出的队列(FIFO)。下面是这两个的的方法使用说明:

·Count 返回列表中的项目数。

·AtLeast 可以用来检查链表的大小,判断当前列表中的指针数目是否大于传递的参数值,如果为True表示列表中的项目数大于传来的参数。

·对于TStack类Push 方法将指针添加到链表的最后,对于TQueue类Push 方法则将指针插入到链表的开始。

·Pop返回链表的末端指针,并将其从链表中删除。

·Peek返回链表的末端指针,但是不将其从链表中删除。

TObjectStack和TObjectQueue类

Contnrs单元中最后两个类是TObjectStack和TObjectQueue类,类的定义如下:

TObjectStack = class(TStack)

public

procedure Push(AObject: TObject);

function Pop: TObject;

function Peek: TObject;

end;

TObjectQueue = class(TQueue)

public

procedure Push(AObject: TObject);

function Pop: TObject;

function Peek: TObject;

end;

这两个类只是TStack和TQueue 类的简单扩展,在链表中保存的是TObject的对象引用,而不是简单的指针。

TIntList 类

到目前为止,我们看到的容器类中保存的都是指针或者对象引用(对象引用其实也是一种指针)。

那么我们能不能在链表中保存原生类型,如Integer,Boolean或者Double等呢。下面的我们定义的类TIntList 类就可以在链表中保存整数,这里我们利用了整数和指针都占用4个字节的存储空间,所以我们可以直接将指针映射为整数。

unit IntList;

interface

uses

Classes;

type

TIntList = class(TList)

protected

function GetItem(Index: Integer): Integer;

procedure SetItem(Index: Integer;

const Value: Integer);

public

function Add(Item: Integer): Integer;

function Extract(Item: Integer): Integer;

function First: Integer;

function IndexOf(Item: Integer): Integer;

procedure Insert(Index, Item: Integer);

function Last: Integer;

function Remove(Item: Integer): Integer;

procedure Sort;

property Items[Index: Integer]: Integer

read GetItem write SetItem; default;

end;

implementation

{ TIntList }

function TIntList.Add(Item: Integer): Integer; begin

Result := inherited Add(Pointer(Item));

end;

function TIntList.Extract(Item: Integer): Integer; begin

Result := Integer(inherited Extract(Pointer(Item))); end;

function TIntList.First: Integer;

begin

Result := Integer(inherited First);

end;

function TIntList.GetItem(Index: Integer): Integer; begin

Result := Integer(inherited Items[Index]);

end;

function TIntList.IndexOf(Item: Integer): Integer; begin

Result := inherited IndexOf(Pointer(Item)); end;

procedure TIntList.Insert(Index, Item: Integer); begin

inherited Insert(Index, Pointer(Item));

end;

function https://www.doczj.com/doc/d316698631.html,st: Integer;

begin

Result := Integer(inherited Last);

end;

function TIntList.Remove(Item: Integer): Integer;

begin

Result := inherited Remove(Pointer(Item));

end;

procedure TIntList.SetItem(Index: Integer;

const Value: Integer);

begin

inherited Items[Index] := Pointer(Value);

end;

function IntListCompare(Item1, Item2: Pointer): Integer; begin

if Integer(Item1) < Integer(Item2) then

Result := -1

else if Integer(Item1) > Integer(Item2) then

Result := 1

else

Result := 0;

end;

procedure TIntList.Sort;

begin

inherited Sort(IntListCompare);

end;

end.

扩展TList,限制类型的对象列表

Begin Listing Two - TMyObjectList

TMyObject = class(TObject)

public

procedure DoSomething;

end;

TMyObjectList = class(TObjectList)

protected

function GetItems(Index: Integer): TMyObject;

procedure SetItems(Index: Integer; AMyObject: TMyObject); public

function Add(aMyObject: TMyObject): Integer;

procedure DoSomething;

function Remove(aMyObject: TMyObject): Integer;

function IndexOf(aMyObject: TMyObject): Integer;

procedure Insert(Index: Integer; aMyObject: TMyObject);

property Items[Index: Integer]: TMyObject

read GetItems write SetItems; default;

end;

...

{ TMyObjectList }

function TMyObjectList.Add(AMyObject: TMyObject): Integer; begin

Result := inherited Add(AMyObject);

end;

procedure TMyObjectList.DoSomething;

var

i: Integer;

begin

for i := 0 to Count-1 do

Items[i].DoSomething;

end;

function TMyObjectList.GetItems(Index: Integer): TMyObject; begin

Result := TMyObject(inherited Items[Index]);

end;

function TMyObjectList.IndexOf(AMyObject: TMyObject): Integer;

begin

Result := inherited IndexOf(AMyObject);

end;

procedure TMyObjectList.Insert(Index: Integer; AMyObject: TMyObject);

begin

inherited Insert(Index, AMyObject);

end;

function TMyObjectList.Remove(AMyObject: TMyObject):

Integer;

begin

Result := inherited Remove(AMyObject);

end;

procedure TMyObjectList.SetItems(Index: Integer;

AMyObject: TMyObject);

begin

inherited Items[Index] := AMyObject;

end;

End Listing Two

TStrings类

出于效率的考虑,Delphi并没有象C++和Java那样将字符串定义为类,因此TList本身不能直接存储字符串,而字符串列表又是使用非常广泛的,为此Borland提供了TStrings类作为存储字符串的基类,应该说是它除了TList类之外另外一个最重要的Delphi容器类。

要注意的是TStrings类本身包含了很多抽象的纯虚的方法,因此不能实例化后直接使用,必须从TStrings 类继承一个基类实现所有的抽象的纯虚方法来进行实际的字符串列表管理。虽然TStrings类本身是一个抽象类,但是它应该说是一个使用了Template模式的模版类,提供了很多事先定义好的算法来实现添加添加、删除列表中的字符串,按下标存取列表中的字符串,对列表中的字符串进行排序,将字符串保存到流中。将每个字符串同一个对象关联起来,提供了键-值对的关联等等。

因为TStrings类本身是个抽象类,无法实例化,因此Delphi提供了一个TStringList的TStrings的子类提供了TStrings类的默认实现,通常在实际使用中,我们都应该使用TStringList类存储字符串列表,代码示意如下:

var TempList: TStrings;

begin

TempList := TStringList.Create;

try

TempList.Add(‘字符串1’);

finally

TempList.Free;

end;

end;

TStrings类的应用非常广泛,很多VCL类的属性都是TStrings类型,比如TMemo组件的Lines属性,TListBox 的Items属性等等。下面将介绍一下TStrings类的常见用法。

TStrings类的常见的用法

根据下标存取列表中的字符串是最常见的一种操作,用法示意如下:

StringList1.Strings[0] := '字符串1';

注意在Delphi中,几乎所有的列表的下标都是以0为底的,也就是说Strings[0]是列表中的第一个字符串。另外,由于Strings属性是字符串列表类的默认属性,因此可以省略Strings,直接用下面的简便方法存取字符串:

StringList1[0] := '字符串1';

定位一个列表中特定的字符串的位置,可以使用IndexOf方法,IndexOf方法将会返回在字符串列表中的第一个匹配的字符串的索引值,如果没有匹配的字符串则返回-1。比如我们可以使用IndexOf方法来察看特定文件是否存在于文件列表框中,代码示意如下:

if FileListBox1.Items.IndexOf('TargetFileName') > -1 ...

有一点不方便的是TStrings类没有提供一个方法可以查找除了第一个匹配字符串外其他同样匹配的字符串的索引,只能是自己遍历字符串列表来实现,这点不如C++中的模版容器类以及相关的模版算法强大和方便。下面是一个遍历字符串列表的示意,代码遍历列表框中的所有字符串,并将其全部转化为大写的字符串:

procedure TForm1.Button1Click(Sender: TObject);var Index: Integer;

begin

for Index := 0 to ListBox1.Items.Count - 1 do

ListBox1.Items[Index] := UpperCase(ListBox1.Items[Index]);

end;

前面我们看到了,要想向字符串列表中添加字符串,直接使用Add方法就可以了,但是Add方法只能将字符串加入到列表的末尾,要想在列表的指定位置添加字符串,需要使用Insert方法,下面代码在列表的索引为2的位置添加了字符串:

StringList1.Insert(2, 'Three');

如果要想将一个字符串列表中的所有字符串都添加到另一个字符串列表中,可以使用AddStrings方法,用法如下:

StringList1.AddStrings(StringList2);

要想克隆一个字符串列表的所有内容,可以使用Assign方法,例如下面的方法将Combox1中的字符串列表复制到了Memo1中:

Memo1.Lines.Assign(ComboBox1.Items);

要注意的是使用了Assign方法后,目标字符串列表中原有的字符串会全部丢失。

同对象关联

前面说了我们可以将字符串同对象绑定起来,我们可以使用AddObject或者InsertObject方法向列表添加同字符串关联的对象,也可以通过Objects属性直接将对象同特定位置的字符串关联。此外TStrings类还提供了IndexOfObject方法返回指定对象的索引,同样的Delete,Clear和Move等方法也可以作用于对象。不过要注意的是我们不能向字符串中添加一个没有同字符串关联的对象。

同视图交互

刚刚学习使用Delphi的人都会为Delphi IDE的强大的界面交互设计功能所震惊,比如我们在窗体上放上一个ListBox,然后在object Inspector中双击它的Items属性(TStrings类型),在弹出的对话框中,见下图,我们输入一些字符串后,点击确定,关闭对话框,就会看到窗体上的ListBox中出现了我们刚才输入的字符串。

可以我们在TStrings和默认的实现类TStringList的源代码中却找不到同ListBox相关的代码,那么这种界面交互是如何做到的呢?

秘密就在于TListBox的Items属性类型实际上是TStrings的基类TListBoxStrings类,我们看一下这个类的定义:

TListBoxStrings = class(TStrings)

private

ListBox: TCustomListBox;

protected

public

function Add(const S: string): Integer; override;

procedure Clear; override;

procedure Delete(Index: Integer); override;

procedure Exchange(Index1, Index2: Integer); override;

function IndexOf(const S: string): Integer; override;

procedure Insert(Index: Integer; const S: string); override;

procedure Move(CurIndex, NewIndex: Integer); override;

end;

可以看到TListBoxStrings类实现了TStrings类的所有抽象方法,同时在内部有一个ListBox的私有变量。我们再看一下TListBoxStrings的Add方法:

function TListBoxStrings.Add(const S: string): Integer;

begin

Result := -1;

if ListBox.Style in [lbVirtual, lbVirtualOwnerDraw] then exit;

Result := SendMessage(ListBox.Handle, LB_ADDSTRING, 0, Longint(PChar(S)));

if Result < 0 then raise EOutOfResources.Create(SInsertLineError);

end;

可以看到TListBoxStrings在内部并没有保存添加的字符串,而是直接向Windows的原生列表盒控件发送消息实现的代码添加,而Windows的原生列表盒是一个MVC的组件,当内部的数据发生变化时,会自动改变视图显示,这就是为什么我们在设计器中输入的字符串会立刻显示在窗体列表框中的原因了。

于是我们也就知道为什么Borland将TStrings设计为一个抽象的类而没有提供一个默认的存储方式,就是因为很多的界面组件在内部对数据的存储有很多不同的方式,Borland决定针对不同的组件提供不同的存储和交互方式。同样的我们要编写的组件如果有TStrings类型的属性,同时也要同界面或者其它资源交互的话,不要使用TStringList来实现,而应该从TStrings派生出新类来实现更好的交互设计。

还有一点要说明的是,Delphi的IDE只在使用Delphi的流机制保存组件到窗体设计文件DFM文件中的时,做了一些特殊的处理,能够自动保存和加载Published的TStrings类型的属性,下面就是一个ListBox储存在窗体设计文件DFM中文本形式示意(在窗体设计阶段,我们可以直接使用View As Text右键菜单命令看到下面的文本),我们可以注意到在设计时我们输入的Items的两个字符串被保存了起来:object ListBox1: TListBox

Left = 64

Top = 40

Width = 145

Height = 73

ItemHeight = 16

Items.Strings = (

'String1'

'String2')

TabOrder = 1

end

随后如果运行程序时,VCL库会使用流从编译进可执行文件的DFM资源中将Items.Strings列表加载到界面上,这样就实现了设计是什么样,运行时也是什么样的所见即所得。

键-值对

在实际开发过程中,我们经常会碰到类似于字典的定位操作的通过键查找相应值的操作,比如通过用户名查找用户相应的登陆密码等。在C++和Java中,标准模版库和JDK都提供了Map类来实现键-值机制,但是Delphi的VCL库却没有提供这样的类,但是TStrings类提供了一个简易的Map替代的实现,那就是Name-Value对。

对于TStrings来说,所谓的Name-Value对,实际上就是’Key=Value’这样包含=号的分割的字符串,等号左边的部分就是Name,等号右边的部分就是Value。TStrings类提供了IndexOfName和Values等属性方法来操作Name-Value对。下面是用法示意:

var

StringList1:TStrings;

Begin

StringList1:=TStringList.Create;

//添加用户名-密码对

StringList1.Add(‘hubdog=aaa’);

StringList1.Add(‘hubcat=bbb’);

….

//根据用户名hubdog查找密码

Showmessage(StringList1.Values[StringList1.IndexOfName(‘hubdog’)]);

End;

从Delphi7开始,TStrings类增加了一个NameValueSeparator属性,我们可以通过这个属性修改默认的Name-Value分割符号为=号以外的其它符号了。还要说明的是,TStrings的Name-Value对中的Name可以不唯一,这有点类似于C++中的MultiMap,这时通过Values[Names[IndexOfName]]下标操作取到的值不一定是我们所需要的,另外TStrings类的Name-Value对的查找定位是采用的遍历的方式,而不同于Java和C++中的Map是基于哈希表或者树的实现,因此查找和定位的效率非常低,不适用于性能要求非常高的场景。不过从Delphi6开始,VCL库中在IniFiles单元中提供了一个基于哈希表的字符串列表类THashedStringList类可以极大的提高查找定位的速度。

THashedStringList类

一般来说,通过键来查找值最简单的办法是遍历列表对列表中的键进行比较,如果相等则获取相应的键值。但是这种简单的办法也是效率最差的一种办法,当列表中的项目比较少时,这种办法还可以接受,但是如果列表中项目非常多的话,这种方法会极大的影响软件的运行速度。这时我们可以使用哈希表来快速的通过键值来存取列表中的元素。由于本书并不是一本数据结构和算法的书,因此我无意在这里讨论哈希表背后的理论知识,我们只要知道哈希可以通过键快速定位相应的值就可以了,对此感兴趣的非计算机专业的人可以去察看相关的书,这里就不赘述了。

Delphi6中提供的THashedStringList类没有提供任何的新的方法,只是对IndexOf和IndexOfName函数通过哈希表进行了性能优化,下面这个例子演示了TStringList和THashedStringList之间的性能差异:

unit CHash;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Inifiles;

type

TForm1 = class(TForm)

Button1: TButton;

procedure Button1Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure FormDestroy(Sender: TObject);

private

{ Private declarations }

HashedList: THashedStringList;

DesList: TStringList;

List: TStringList;

public

{ Public declarations }

procedure Hash;

procedure Iterate;

end;

var

Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);

var

I:Integer;

begin

Screen.Cursor := crHourGlass;

try

//初始化系统

for I := 0 to 5000 do

begin

HashedList.Add(IntToStr(i));

List.Add(IntToStr(i));

end;

Hash;

DesList.Clear;

Iterate;

finally

Screen.Cursor := crDefault;

end;

end;

procedure TForm1.Hash;

var

I, J: Integer;

begin

//基于哈希表的定位

for I := 3000 to 4000 do

begin

DesList.Add(IntToStr(HashedList.IndexOf(IntToStr(I))));

end;

end;

procedure TForm1.Iterate;

var

I, J: Integer;

begin

//基于遍历方式定位

for I := 3000 to 4000 do

begin

DesList.Add(IntToStr(List.IndexOf(IntToStr(I))));

end;

end;

procedure TForm1.FormCreate(Sender: TObject);

begin

HashedList := THashedStringList.Create;

DesList := TStringList.Create;

List := TStringList.Create;

end;

procedure TForm1.FormDestroy(Sender: TObject);

begin

HashedList.Free;

DesList.Free;

List.Free;

end;

end.

上面代码中的Hash过程,采用了新的THashedStringList类来实现的查找,而Iterate过程中使用了原来的TStringList类的IndexOfName来实现的查找。采用GpProfile(注:GpProfile的用法参见工具篇的性能分析工具GpProfile章节)对两个过程进行了性能比较后,从下图可以看到Hash执行同样查找动作只用了0.7%的时间,而Iterate方法则用了99.3%的时间,可以看到在字符串列表项目数在几千的数量级别时,基于哈希表的查询速度是原有方法的100多倍。

不过要说明的是,THashedStringList同TStringList类相比,虽然查找的速度大大提高了,但是在添加、删除字符串后再次进行查找操作时,需要重新计算哈希函数,所以如果频繁的进行删除或者添加同查找的复合操作,执行的速度很有可能比TStringList还要慢,这是使用时需要注意的。

TBucketList和TObjectBucketList类

从Delphi6开始,VCL的Contnrs单元中又增加了两个新的容器类TBucketList和TObjectBucketList。TBucketList实际上也是一个简单基于哈希表的指针-指针对列表。接口定义如下:

TBucketList = class(TCustomBucketList)

public

destructor Destroy; override;

procedure Clear;

function Add(AItem, AData: Pointer): Pointer;

function Remove(AItem: Pointer): Pointer;

function ForEach(AProc: TBucketProc; AInfo: Pointer = nil): Boolean;

procedure Assign(AList: TCustomBucketList);

function Exists(AItem: Pointer): Boolean;

function Find(AItem: Pointer; out AData: Pointer): Boolean;

property Data[AItem: Pointer]: Pointer read GetData write SetData; default;

end;

类的Add方法现在接受两个参数AItem和AData,我们可以把它看成是指针版的Map实现(从容器类来看, Delphi从语言的灵活性来说不如C++,为了实现不同类型的哈希Map容器,Delphi需要派生很多的类,而C++的Map是基于模版技术来实现的,容器元素的类型只要简单的声明一下就能指定了,使用起来非常方便。而从简单性来说,则不如Java的容器类,因为Delphi中的String是原生类型,而不是类,并且Delphi 还提供对指针的支持,因此要为指针和字符串提供不同的Map派生类),类中的Exists和Find等方法都是通过哈希表来实现快速数据定位的。同时,同一般的列表容器类不同,TBucketList不提供通过整数下标获取列表中的元素的功能,不过我们可以使用ForEach方法来遍历容器内的元素。

TObjectBucketList是从TBucketList派生的基类,没有增加任何新的功能,唯一的不同之处就是容器内的元素不是指针而是对象了,实现了更强的类型检查而已。

其它容器类

TThreadList类

TThreadList类实际上就是一个线程安全的TList类,每次添加或者删除容易中指针时,TThreadList会调用EnterCriticalSection函数进入线程阻塞状态,这时其它后续发生的对列表的操作都会阻塞在那里,直到TThreadList调用UnLockList释放对列表的控制后才会被依次执行。在多线程开发中,我们需要使用TThreadList来保存共享的资源以避免多线程造成的混乱和冲突。还要注意的是TThreadList有一个Duplicates布尔属性,默认为True,表示列表中不能有重复的指针。设定为False将允许容器内有重复的元素。

TInterfaceList类

在Classes单元中,VCL还定义了一个可以保存接口的列表类。我们可以向列表中添加接口类型,这个类的操作方法同其它的列表类没有什么区别,只不过在内部使用TThreadList作为容器实现了线程安全。拟容器类TBits类

在Classes.pas还有一个特殊的TBits类,接口定义如下:

TBits = class

public

destructor Destroy; override;

function OpenBit: Integer;

property Bits[Index: Integer]: Boolean read GetBit write SetBit; default;

property Size: Integer read FSize write SetSize;

end;

它可以按位储存布尔值,因此可以看成是一个原生的Boolean值的容器类,但是它缺少列表类的很多方法和特性,不能算是一个完整的容器,因此我们称它为拟容器类。

在我们开发过程中,经常需要表示一些类似于开关的二元状态,这时我们用TBits来表示一组二元状态非常方便,同时TBits类的成员函数主要是用汇编语言写的,位操作的速度非常快。二元状态组的大小通过设定TBits类的Size属性来动态的调整,存取Boolean值可以通过下标来存取TBits类的Bits属性来实现。至于OpenBit函数,它返回第一个不为True的Boolean值的下标。从接口定义可以看出,TBits类接口非常简单,提供的功能也很有限,我猜测这只是Borland的研发队伍满足内部开发有限需要的类,并不是作为一个通用类来设计的,比如它没有开放内部数据存取的接口,无法获得内部数据的表达,进而无法实现对状态的保存和加载等更高的需求。

TCollection类

前面我们提到了Delphi的IDE能够自动将字符串列表保存在DFM文件中,并能在运行时将设计期编辑的字符串列表加载进内存(也就是我们通常所说的类的可持续性)。TStrings这种特性比较适合于保存一个对象同多个字符串数据之间关联,比较类似于现实生活中一个人同多个Email账户地址之间的关系。但是,TStrings类型的属性有一个很大的局限那就是,它只能用于设计时保存简单的字符串列表,而不能保存复杂对象列表。而一个父对象同多个子对象之间的聚合关系可能更为常见,比如一列火车可能有好多节车厢构成,每节车厢都有车厢号,车厢类型(卧铺,还是硬座),车厢座位数,车厢服务员名称等属性构成。如果我们想在设计期实现对火车的车厢定制的功能,并能保存车厢的各个属性到窗体文件中,则车厢集合属性定义为TStrings类型的属性是行不通的。

对于这个问题,Delphi提供了TCollection容器类属性这样一个解决方案。TCollection以及它的容器元素TCollectionItem的接口定义如下:

TCollection = class(TPersistent)

protected

procedure Added(var Item: TCollectionItem); virtual; deprecated;

procedure Deleting(Item: TCollectionItem); virtual; deprecated;

property NextID: Integer read FNextID;

procedure Notify(Item: TCollectionItem; Action: TCollectionNotification); virtual;

{ Design-time editor support }

function GetAttrCount: Integer; dynamic;

function GetAttr(Index: Integer): string; dynamic;

function GetItemAttr(Index, ItemIndex: Integer): string; dynamic;

procedure Changed;

function GetItem(Index: Integer): TCollectionItem;

procedure SetItem(Index: Integer; Value: TCollectionItem);

procedure SetItemName(Item: TCollectionItem); virtual;

procedure Update(Item: TCollectionItem); virtual;

property PropName: string read GetPropName write FPropName;

property UpdateCount: Integer read FUpdateCount;

public

constructor Create(ItemClass: TCollectionItemClass);

destructor Destroy; override;

function Owner: TPersistent;

function Add: TCollectionItem;

procedure Assign(Source: TPersistent); override;

procedure BeginUpdate; virtual;

procedure Clear;

procedure Delete(Index: Integer);

procedure EndUpdate; virtual;

function FindItemID(ID: Integer): TCollectionItem;

function GetNamePath: string; override;

function Insert(Index: Integer): TCollectionItem;

property Count: Integer read GetCount;

property ItemClass: TCollectionItemClass read FItemClass;

property Items[Index: Integer]: TCollectionItem read GetItem write SetItem;

end;

TCollectionItem = class(TPersistent)

protected

procedure Changed(AllItems: Boolean);

function GetOwner: TPersistent; override;

function GetDisplayName: string; virtual;

procedure SetCollection(Value: TCollection); virtual;

procedure SetIndex(Value: Integer); virtual;

procedure SetDisplayName(const Value: string); virtual;

public

constructor Create(Collection: TCollection); virtual;

destructor Destroy; override;

function GetNamePath: string; override;

property Collection: TCollection read FCollection write SetCollection;

property ID: Integer read FID;

property Index: Integer read GetIndex write SetIndex;

property DisplayName: string read GetDisplayName write SetDisplayName;

end;

TCollection类是一个比较复杂特殊的容器类。但是初看上去,它就是一个TCollectionItem对象的容器类,同列表类TList类似,TCollection类也维护一个TCollectionItem对象索引数组,Count属性表示容器中包含的TCollectionItem的数目,同时也提供了Add和Delete方法来添加和删除TCollectionItem对象以及通过下标存取TCollectionItem的属性。看上去和容器类区别不大,但是在VCL内部用于保存和加载组件的TReader 和TWriter类提供了两个特殊的方法WriteCollection和ReadCollection用于加载和保存TCollection类型的集合属性。IDE就是通过这两个方法实现对TCollection类型属性的可持续性。

假设现在需要设计一个火车组件TTrain,TTrain组件有一个TCollection类型的属性Carriages表示多节车厢构成的集合属性,每个车厢则对应于集合属性的元素,从TCollectionItem类继承,有车厢号,车厢类型(卧铺,还是硬座),车厢座位数,车厢服务员名称等属性,下面是我设计的组件的接口:

type

//车厢类型,硬座、卧铺

TCarriageType = (ctHard, ctSleeper);

//车厢类

TCarriageCollectionItem = class(TCollectionItem)

//车厢号码

property CarriageNum: Integer read FCarriageNum write FCarriageNum;

//座位数

property SeatCount: Integer read FSeatCount write FSeatCount;

//车厢类型

property CarriageType: TCarriageType read FCarriageType write FCarriageType;

//服务员名称

property ServerName: string read FServerName write FServerName;

end;

TTrain=class;

//车厢容器属性类

TCarriageCollection = class(TCollection)

private

FTrain:TTrain;

function GetItem(Index: Integer): TCarriageCollectionItem;

procedure SetItem(Index: Integer; const Value: TCarriageCollectionItem);

protected

function GetOwner: TPersistent; override;

public

constructor Create(A Train: TTrain);

function Add: TCarriageCollectionItem;

property Items[Index: Integer]: TCarriageCollectionItem read GetItem

write SetItem; default;

end;

//火车类

TTrain = class(TComponent)

private

FItems: TCarriageCollection;

procedure SetItems(Value: TCarriageCollection);

public

constructor Create(AOwner: TComponent); override;

destructor Destroy; override;

published

property Carriages: TCarriageCollection read FItems write SetItems;

end;

其中车厢类的定义非常简单,只是定义了四个属性。而车厢集合类重定义了静态的Add方法以及Items属性,其返回结果类型改为了TCarriageCollectionItem,下面是车厢集合类的实现代码:

function TCarriageCollection.Add: TCarriageCollectionItem;

begin

Result:=TCarriageCollectionItem(inherited Add);

end;

constructor TCarriageCollection.Create(ATrain: TTrain);

begin

inherited Create(TCarriageCollectionItem);

FTrain:=ATrain;

end;

function TCarriageCollection.GetItem(

Index: Integer): TCarriageCollectionItem;

begin

Result := TCarriageCollectionItem(inherited GetItem(Index));

end;

function TCarriageCollection.GetOwner: TPersistent;

begin

Result:=FTrain;

end;

procedure TCarriageCollection.SetItem(Index: Integer;

const Value: TCarriageCollectionItem);

begin

inherited SetItem(Index, Value);

end;

其中Add,GetItem和SetItem都非常简单,就是调用基类的方法,然后将基类的方法的返回结果重新映射为TCollectionItem类型。而构造函数中将TTrain组件作为父组件传入,并重载GetOwner方法,返回TTrain 组件,这样处理的原因是IDE会在保存集合属性时调用集合类的GetOwner确认属性的父控件是谁,这样才能把集合属性写到DFM文件中时,才能存放到正确的位置下面,建立正确的聚合关系。

而火车组件的实现也非常简单,只要定义一个Published Carriages属性就可以了,方法实现代码如下:constructor TTrain.Create(AOwner: TComponent);

begin

FItems := TCarriageCollection.Create(Self);

end;

structor TTrain.Destroy;

begin

FItems.Free;

inherited;

end;

procedure TTrain.SetItems(Value: TCarriageCollection);

begin

FItems.Assign(Value);

end;

下面将我们的组件注册到系统面板上之后,就可以在窗体上放上一个TTrain组件,然后然后选中Object Inspector,然后双击Carriages属性,会显示系统默认的集合属性编辑器,使用Add按钮向列表中添加两个车厢,修改一下属性,如下图所示意:

从上面的属性编辑器我们,可以看到默认情况下,属性编辑器列表框是按项目索引加上一个横杠来显示车厢的名称,看起来不是很自然。要想修改显示字符串,需要重载TCarriageCollectionItem的GetDisplayName 方法。修改后的GetDisplayName方法显示车厢加车厢号码:

function TCarriageCollectionItem.GetDisplayName: string;

begin

Result:='车厢'+IntToStr(CarriageNum);

end;

示意图:

保存一下文件,使用View As Text右键菜单命令察看一下DFM文件,我们会看到我们设计的车厢类的属性确实都被写到了DFM文件中,并且Carriages属性的父亲就是Train1:

object Train1: TTrain

Carriages = <

item

CarriageNum = 1

SeatCount = 100

CarriageType = ctHard

ServerName = '陈省'

end

item

CarriageNum = 2

SeatCount = 200

CarriageType = ctHar

ServerName = 'hubdog'

end>

Left = 16

Top = 8

End

TOwnedCollection

从Delphi4开始,VCL增加了一个TOwnedCollection类,它是TCollection类的子类,如果我们的TCarriageCollection类是从TOwnedCollection类继承的,这时我们就不再需要向上面重载GetOwner方法并返回父控件给IDE,以便TCarriageCollection属性能出现在Object Inspector中了。

总结

本章中我介绍了几乎所有VCL中重要的容器类,其中TList及其子类相当于通用的容器类,虽然不如C++和Java功能那么强大,但是用好了已经足以满足我们90%的开发需要,而TStrings及其子类,还有TCollection 则是实现所见即所得设计的关键类,对于开发灵活强大的自定义组件来说是必不可少的。

实验3 类的定义、对象的建立与使用

实验报告_实验3 类的定义、对象的建立与使用(学 生学号_姓名) 实验目的: 1、理解C++中class与struct的区别; 2、掌握类的定义以及成员函数的定义方法; 3、掌握对象的定义和对象成员的访问方式; 4、熟悉this指针的基本用法。 实验内容 二、((基础题)请按照下列要求定义一个Clock时钟类,并创建对象,再调用相应方法: 程序代码: //日期类的应用 #include using namespace std; class Clock // 定义日期类 { public: // 定义公有成员函数 void setTime(int h, int m, int s); void showTime(); private: // 定义私有数据成员 int hour; int minute;

int second; }; // 类定义体的结束 //类实现部分 void Clock::setTime(int h, int m, int s) { hour = h; minute = m; second = s; } void Clock::showTime() { cout << "设置时间为" << hour <<":"<< minute <<":"<< second << endl; } int main() { Clock now; now.setTime(8,30, 0); now.showTime(); return 0; } 三、(基础题)请按要求,编写程序(请将类的定义、成员函数的实现、类的使用分开): rect.h代码: #include

Delphi如何使用基本的绘图函数绘制统计图

一个windows自带的画图工具是无论如何也不能满足我们的画图需要的,很多效果都需要我们在另外的工具中来实现。这些高级的功能是如何实现的呢,如何操纵一些基本的属性和函数,让它们最终能作出我们想要的效果呢?这里我们以绘制统计图来说明这些问题。 解决思路―― 这里,我们暂且先撇开具体的问题,综合地一下讨论画图的问题。 画图工具是基本元素的具体实现,对于我们初学者来说,还是有很好的参考价值的,在delphi 5中有一个自带的工程例子“……Borland\Delphi5\Demos\Doc\Graphex”,这个例子可以实现一些基本的绘图功能。对这个例子多加修改,一定会有所收获的。这里就不列出它的详细代码了,有心的读者可以自己找到这个例子。我这里只是想综合地讨论这方面的问题。使用DELPHI编写绘图软件的灵魂就在于操作画布,画笔和刷子,尽可能地挖掘它们的属性和相关参数的设置。 (一)画布 画布,画笔和刷子之间的关系很明了.其实,画笔和刷子都是画布的一个属性.而画布也只是TForm,TImage,TShape等组件对象的一个属性,专门负责与图象相关的信息打交道.它的主要作用可以概括如下几点: 1.指定使用画笔,刷子和字体的使用类型; 2.绘制和填充指定形状的线或图形; 3.修饰和改变图象; 画布的主要属性有: Brush--指定填充图形和背景的样式 CanvasOrientation--指定画布的定位类型,有coLeftToRight, coRightToLeft两个属性; ClipRect--指定剪切矩形的边界; CopyMode--指定图形图象的复制模式; Font--指定画布上使用的字体; Handle--为画布指定窗口GDI对象的设备描述表; LockCount--指定画布被别的线程锁定的次数; Pen--指定画布上使用的画笔,具体见下面描述; PenPos--指定画笔当前的位置; Pixels--指定当前剪切矩形的象素颜色; TextFlags--指定字体在画布上的显示方式,有ETO_CLIPPED,ETO_OPAQUE,ETO_RTLREADING,ETO_GL YPH_INDEX,ETO_IGNORELANGUAGE,ETO_NUMERICSLOCALETO_NUMERIC SLATIN等值可选; 画布相关的API函数及其注释如下: Arc--按指定方式画一条弧; BrushCopy--把位图复制到指定的画布的矩形中,用画布刷子颜色替换位图的颜色; Chord--按指定方式画弦; CopyRect--从一个矩形区域复制部分图象到另一个矩形区域; Draw--用指定参数在指定位置画图; DrawFocusRect--按指定焦点风格,通过异或操作来绘制一焦点矩形; Ellipse--按指定参数画一椭圆; FillRect--按指定的刷子填充一矩形; FloodFill--使用当前选定的刷子填充指定设备描述表中的一块区域;

类的定义和对象的创建

实验二类的定义和对象的创建 实验目的 1、学习定义类和使用类 2、学习创建的对象和使用对象 实验内容 1、定义一个Student类。其中定义有“学号”“姓名”“班级”“性别”“年龄”等属性,定 义一个无参数的构造器和至少一个有参数的构造器,定义“获得学号”“获得姓名”“获得班级”“获得性别”“获得年龄”“修改年龄”等方法。另外定义一个方法: public String toString( ) 把Student类的对象的所有属性信息组合成一个字符串,并检验这个功能的程序体现。 public class Student { private int 学号; private String 姓名; private String 班级; private char 性别; private int 年龄; public Student(int a, String b, String c, char d, int e) { 学号= a; 姓名= b; 班级= c; 性别= d; 年龄= e; } public Strudent() { this(0, "张三" ,"软件0901" ,'男', 19); } public int get学号() { return 学号; } public String get姓名() { return 姓名; } public String get班级() { return 班级; } public char get性别() { return 性别; } public int get年龄()

{ return 年龄; } public void set学号(int a) { 学号=a; } public void set姓名(String a ) { 姓名=a; } public void set班级(String a) { 班级= a; } public void set性别( char a) { 性别= a ; } public void set年龄(int a) { 年龄= a; } public String toString() { return "该学生的学号为"+ 学号+ " 姓名为"+姓名+" 班级为"+班级+ " 性别为" +性别+ " 年龄为" +年龄"; } } 2、编程实现圆类,其中包括计算圆周长和面积的方法,并测试方法的正确性。 public class Yuan { private double X, Y, R; public Yuan(double a, double b, double c) { X=a; Y=b; R=c; } public double MianJi() { return 3.1416*R*R; } public double ZhouChang() { return 2*3.1416*R; } public static void main(String[] args) { Yuan s=new Yuan(2,3,4); System.out.println("该圆的面积是"+ s.MianJi()); System.out.println("该圆的周长是"+ s.ZhouChang()); } }

delphi数学模块函数、过程大全

function ArcCos(const X : Extended) : Extended; overload; function ArcCos(const X : Double) : Double; overload; function ArcCos(const X : Single) : Single; overload; function ArcSin(const X : Extended) : Extended; overload; function ArcSin(const X : Double) : Double; overload; function ArcSin(const X : Single) : Single; overload; function ArcTan2(const Y, X: Extended): Extended; procedure SinCos(const Theta: Extended; var Sin, Cos: Extended) register; function Tan(const X: Extended): Extended; function Cotan(const X: Extended): Extended; { 1 / tan(X), X <> 0 } function Secant(const X: Extended): Extended; { 1 / cos(X) } function Cosecant(const X: Extended): Extended; { 1 / sin(X) } function Hypot(const X, Y: Extended): Extended; { Sqrt(X**2 + Y**2) } function RadToDeg(const Radians: Extended): Extended; inline; { Degrees := Radians * 180 / PI } function RadToGrad(const Radians: Extended): Extended; inline; { Grads := Radians * 200 / PI } function RadToCycle(const Radians: Extended): Extended; inline; { Cycles := Radians / 2PI } function DegToRad(const Degrees: Extended): Extended; inline; { Radians := Degrees * PI / 180} function DegToGrad(const Degrees: Extended): Extended; function DegToCycle(const Degrees: Extended): Extended; function GradToRad(const Grads: Extended): Extended; inline; { Radians := Grads * PI / 200 } function GradToDeg(const Grads: Extended): Extended; function GradToCycle(const Grads: Extended): Extended; function CycleToRad(const Cycles: Extended): Extended; inline; { Radians := Cycles * 2PI } function CycleToDeg(const Cycles: Extended): Extended; function CycleToGrad(const Cycles: Extended): Extended; { Hyperbolic functions and inverses } function Cot(const X: Extended): Extended; inline; { alias for Cotan } function Sec(const X: Extended): Extended; inline; { alias for Secant } function Csc(const X: Extended): Extended; inline; { alias for Cosecant } function Cosh(const X: Extended): Extended; function Sinh(const X: Extended): Extended; function Tanh(const X: Extended): Extended; function CotH(const X: Extended): Extended; inline; function SecH(const X: Extended): Extended; inline; function CscH(const X: Extended): Extended; inline; function ArcCot(const X: Extended): Extended; { IN: X <> 0 } function ArcSec(const X: Extended): Extended; { IN: X <> 0 } function ArcCsc(const X: Extended): Extended; { IN: X <> 0 } function ArcCosh(const X: Extended): Extended; { IN: X >= 1 } function ArcSinh(const X: Extended): Extended;

C中类与类定义及具体使用方法

C中类与类定义及具体 使用方法 IMB standardization office【IMB 5AB- IMBK 08- IMB 2C】

类模板 类模板也称为类属类或类生成类,是为类定义的一种模式,它使类中的一些数据成员和成员函数的参数或返回值可以取任意的数据类型。类模颁布是一个具体的类,它代表着一族类,是这一族类的统一模式。使用类模板就是要将它实例化为具体的类。 定义类模板的一般形式为: template class类名 { //…… } 其中,template是声明类模板的关键字;template后面的尖括号不能省略;数据类型参数标识符是类模板中参数化的类型名,当实例化类模板时,它将由一个具体的类型来代替。 定义类模板时,可以声明多个类型参数标识符,各标识符之间用逗号分开。 类定义中,凡要采用标准数据类型的数据成员、成员函数的参数或返回类型的前面都要加上类型标识符。 如果类中的成员函数要在类的声明之外定义,则它必须是模板函数。其定义形式为: template 数据类型参数标识符类名<数据类型参数标识符>∷函数名(数据类型参数标识符形参1,……,数据类型参数标识符形参n) { 函数体 } 模板类 将类模板的模板参数实例化后生成的具体的类,就是模板类。由类模板生成模板类的一般形式为:

类名<数据类型参数标识符>对象名1,对象名2,…,对象名n; 这里的数据类型参数标识符对应的是对象实际需要的数据类型。 应用举例 例函数模板的声明和模板函数的生成的例。 #include<> template//声明模板函数,T为数据类型参数标识符voidswap(T&x,T&y)//定义模板函数 { Tz;//变量z可取任意数据类型及模板参数类型T z=y; y=x; x=z; } voidmain() { intm=1,n=5; doublea=,b=; cout<<”m=”<

DELPHI常用函数说明

一、数据类型转换函数1 在我们编写程序当中,根据不同情况,会使用到多种数据类型。当要对不同的类型进行操作时,必须要将不同的类型转换成同样的类型。因此熟练地掌握数据类型的转换是非常重要的。 1.FloatToStr 功能说明:该函数用于将“浮点型”转换成“字符型”。 参考实例: Edit1.Text := FloatToStr(1.981); 2.IntToStr 功能说明:该函数用于将“整数型”转换成“字符型”。 参考实例: S := IntToStr(10);(注:S为String类型变量。) 3.IntToHex 功能说明:该函数用于将“十进制”转换成“十进制”。该函数有二个参数1。第一个参数为要转换的十进制数据,第二个参数是指定使用多少位来显示十六进制数据。 参考实例: Edit1.Text := IntToHex('100', 2);

执行结果,Edit1.Text等于64。 注意:Delphi没有提供专门的“十六进制”转换为“十进制”的函数。使用StrToInt函数可以实现这个功能。具体代码是:I := StrToInt('S\' + '64'); 这时I等于100。加上一个'S\'即可将“十六进制”转换为“十进制”。 4.StrToInt 功能说明:该函数用于将“字符型”转换成“整数型”。 参考实例: I := StrToInt('100'); 注意:不能转换如StrToInt('ab')或StrToInt('好')这样的类型,因为他们并不存在数字型。 5.StrToFloat 功能说明:该函数用于将“字符型”转换成“浮点型”。 参考实例: N := StrToFloat(Edit1.Text); 注意:Edit1.Text中的内容为1.981(凡在Edit 控件中显示的文本均为字符串)。N为Double类型,用于保存转换后的浮点型数据。

Delphi函数大全

Delphi函数大全 首部function Languages: TLanguages; $[ 功能返回系统语言对象 说明通过此函数可以得到系统的语言环境 参考type 例子 12a12c12a12c. 参考 例子:= IsValidIdent; ━━━━━━━━━━━━━━━━━━━━━ 首部function IntToStr(Value: Integer): string; overload; $[ 首部function IntToStr(Value: Int64): string; overload; $[ 功能返回整数Value转换成字符串 说明Format('%d', [Value]) 参考function 例子:= IntToStr; ━━━━━━━━━━━━━━━━━━━━━ 首部function IntToHex(V alue: Integer; Digits: Integer): string; overload; $[ 首部function IntToHex(V alue: Int64; Digits: Integer): string; overload; $[ 功能返回整数Value转换成十六进制表现结果;Format('%.*x', [Digits, Value]) 说明参数Digits指定字符最小宽度;最小宽度不足时将用0填充 参考function 例子:= IntToHex, ; ━━━━━━━━━━━━━━━━━━━━━ 首部function StrToInt(const S: string): Integer; $[ 功能返回字符串S转换成整数 说明字符串非整数表达时将引起异常 参考procedure 例子:= StrToInt; ━━━━━━━━━━━━━━━━━━━━━ 首部function StrToIntDef(const S: string; Default: Integer): Integer; $[ 功能返回字符串S转换成整数 说明字符串非整数表达时则返回默认值Default 参考procedure 例子:= StrToIntDef, 0); ━━━━━━━━━━━━━━━━━━━━━ 首部function TryStrToInt(const S: string; out Value: Integer): Boolean; $[ 功能返回字符串S转换成整数V alue是否成功 说明字符串非整数表达时返回False并且Value将输出为0 参考procedure 例子 ..);打开失败则返回负数 参考function

实验6 类的定义与使用--练习

实验6 类的定义与使用 一、实验目的和任务 类的定义与使用 1)掌握类的概念、定义格式、类与结构的关系、类的成员属性和类的封装性; 2)掌握类对象的定义; 3)理解类的成员的访问控制的含义,公有、私有和保护成员的区别; 4)掌握构造函数和析构函数的含义与作用、定义方式和实现,能够根据要求正确定义和重载构造函数。能够根据给定的要求定义类并实现类的成员函数; 二、实验原理介绍 通过建立类及对象,用类的成员函数和对象访问类的成员; 利用建立类的构造函数,完成类的成员的初始化工作; 三、实验设备介绍 软件需求: Visual C++ 6.0 四、实验内容和步骤 1、声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,有两个公有成员函数run、stop。其中rank为枚举类型,声明为enum CPU_Rank { p1=1,p2,p3,p4,p5,p6,p7},frequency为单位是MHz的整形数,voltage为浮点型的电压值。观察构造函数和析构函数的调用顺序。 2、声明一个简单的Computer类,有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,有两个公有成员函数run、stop。cpu为CPU类的一个对象,ram为RAM类的一个对象,cdrom为CDROM类的一个对象,声明并实现这个类。 3、(选做)设计一个用于人事管理的People(人员)类。考虑到通用性,这里只抽象出所有类型人员都具有的属性:number(编号)、sex(性别)、birthday(出生日期)、id(身份证号)等等。其中“出生日期”声明为一个“日期”类内嵌子对象。用成员函数实现对人员信息的录入和显示。要求包括:构造函数和析构函数、拷贝构造函数、内联成员函数。组合。 思考题 1、注意类的定义; 2、类的成员函数的访问方式; 五、注意事项和要求 要求学生要提前准备实验的内容 实验完成后要求写出实验报告

(DELPHI)API函数大全

(DELPHI)API函数大全 1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接WNetAddConnection2 创建同一个网络资源的连接WNetAddConnection3 创建同一个网络资源的连接WNetCancelConnection 结束一个网络连接 WNetCancelConnection2 结束一个网络连接 WNetCloseEnum 结束一次枚举操作 WNetConnectionDialog 启动一个标准对话框,以便建立同网络资源的连接WNetDisconnectDialog 启动一个标准对话框,以便断开同网络资源的连接WNetEnumResource 枚举网络资源 WNetGetConnection 获取本地或已连接的一个资源的网络名称WNetGetLastError 获取网络错误的扩展错误信息WNetGetUniversalName 获取网络中一个文件的远程名称以及/或者UNC (统一命名规范)名称 WNetGetUser 获取一个网络资源用以连接的名字 WNetOpenEnum 启动对网络资源进行枚举的过程 2. API之消息函数 BroadcastSystemMessage 将一条系统消息广播给系统中所有的顶级窗口GetMessagePos 取得消息队列中上一条消息处理完毕时的鼠标指针屏幕位置GetMessageTime 取得消息队列中上一条消息处理完毕时的时间PostMessage 将一条消息投递到指定窗口的消息队列PostThreadMessage 将一条消息投递给应用程序RegisterWindowMessage 获取分配给一个字串标识符的消息编号ReplyMessage 答复一个消息 SendMessage 调用一个窗口的窗口函数,将一条消息发给那个窗口SendMessageCallback 将一条消息发给窗口 SendMessageTimeout 向窗口发送一条消息 SendNotifyMessage 向窗口发送一条消息 3. API之文件处理函数 CloseHandle 关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等 CompareFileTime 对比两个文件的时间 CopyFile 复制文件 CreateDirectory 创建一个新目录 CreateFile 打开和创建文件、管道、邮槽、通信服务、设备以及控制台CreateFileMapping 创建一个新的文件映射对象 DeleteFile 删除指定文件

类的定义与使用

一、实验目的和任务 类的定义与使用 1)掌握类的概念、定义格式、类与结构的关系、类的成员属性和类的封装性; 2)掌握类对象的定义; 3)理解类的成员的访问控制的含义,公有、私有和保护成员的区别; 4)掌握构造函数和析构函数的含义与作用、定义方式和实现,能够根据要求正确定义和重载构造函数。能够根据给定的要求定义类并实现类的成员函数; 二、实验原理介绍 验证性实验; 通过建立类及对象,用类的成员函数和对象访问类的成员; 利用建立类的构造函数,完成类的成员的初始化工作; 三、实验设备介绍 软件需求: Visual C++ 6.0 四、实验内容 1、声明一个CPU类,包含等级(rank)、频率(freauency)、电压(voltage)等属性,有两个公有成员函数run、stop。其中rank为枚举类型,声明为enum CPU_Rank { p1=1,p2,p3,p4,p5,p6,p7},frequency为单位是MHz的整形数,voltage为浮点型的电压值。观察构造函数和析构函数的调用顺序。 实验原理:构造CPU类私有成员为等级(rank)、频率(freauency)、电压(voltage),其中rank为枚举类型,声明为enum CPU_Rank { p1=1,p2,p3,p4,p5,p6,p7},然后设置public 的构造函数CPU,有频率和电压。使频率f等于形参x,电压u等于y,此为构造的函数。然后运用析构函数,其符号为~,运用析构函数。一个类只能定义一个析构函数,析构函数

没有形参,且其顺序较特殊,对于含有多个对象的程序,先创建的对象后析构,后创建的对象先析构。所以析构函数出现在最后。此程序中,三个对象CPU run stop ,CPU析构,在主函数中运行了构造函数,run stop执行后析构。 实验源程序: #include class CPU {private: int f; double u; enum CPU_Rank{P1=1,P2,P3,P4,P5,P6,P7}; public: CPU(int x,double y) { f=x; u=y; cout<<"调用构造函数"<<"f="<

(3)protected:表示只能从其所在类和所在类的子类进行访问。 (4)internal:只有其所在类才能访问。 (5)private:只有.NET中的应用程序或库才能访问。 (6)abstract:抽象类,不允许建立类的实例。 (7)sealed:密封类,不允许被继承。 类的成员可以分为两大类:类本身所声明的以及从基类中继承来的。 类的成员包括以下类型: 字段:即类中的变量或常量,包括静态字段、实例字段、常量和只读字段。 方法:包括静态方法和实例方法。 属性:按属性指定的get方法和Set方法对字段进行读写。属性本质上是方法。 事件:代表事件本身,同时联系事件和事件处理函数。 索引指示器:允许象使用数组那样访问类中的数据成员。 操作符重载:采用重载操作符的方法定义类中特有的操作。 构造函数和析构函数。 1.2 对象 对象是类的实例,是OOP应用程序的一个组成部件。这个组成部件封装了部分应用程序,这部分应用程序可以是一个过程、一些数据

Delphi函数大全

Delphi函数大全 Abort 函数引起放弃的意外处理 Abs 函数绝对值函数 AddExitProc 函数将一过程添加到运行时库的结束过程表中Addr 函数返回指定对象的地址 AdjustLineBreaks 函数将给定字符串的行分隔符调整为CR/LF序列Align 属性使控件位于窗口某部分 Alignment 属性控件标签的文字位置 AllocMem 函数在堆栈上分配给定大小的块 AllowGrayed 属性允许一个灰度选择 AnsiCompareStr 函数比较字符串(区分大小写)AnsiCompareText 函数比较字符串(不区分大小写)AnsiLowerCase 函数将字符转换为小写 AnsiUpperCase 函数将字符转换为大写 Append 函数以附加的方式打开已有的文件 ArcTan 函数余切函数 AssignFile 函数给文件变量赋一外部文件名 Assigned 函数测试函数或过程变量是否为空 AutoSize 属性自动控制标签的大小 BackgroundColor 属性背景色 BeginThread 函数以适当的方式建立用于内存管理的线程BevelInner 属性控件方框的内框方式 BevelOuter 属性控件方框的外框方式 BevelWidth 属性控件方框的外框宽度 BlockRead 函数读一个或多个记录到变量中 BlockWrite 函数从变量中写一个或多个记录 BorderStyle 属性边界类型 BorderWidth 属性边界宽度 Break 命令终止for、while、repeat循环语句 Brush 属性画刷 Caption 属性标签文字的内容 ChangeFileExt 函数改变文件的后缀 ChDir 函数改变当前目录 Checked 属性确定复选框选中状态 Chr 函数返回指定序数的字符 CloseFile 命令关闭打开的文件 Color 属性标签的颜色 Columns 属性显示的列数 CompareStr 函数比较字符串(区分大小写) Concat 函数合并字符串 Continue 命令继续for、while、repeat的下一个循环 Copy 函数返回一字符串的子串 Cos 函数余弦函数 Ctl3D 属性是否具有3D效果

相关主题
文本预览
相关文档 最新文档