C++ Builder XE2随意学习 (6) > System

在FireMonkey类库中,System命名空间下有Classes Contnrs Sysutils TInterfacedObject TObject五个子空间。

cbw1

1) Sysutils

从自己的编程经验来看,应该先看Sysutils,这是些工具,基本不用其它的基础。进入查看,竟然全是Exception。

先看一个AxisException,稍微深入一点,冏啊,居然在pas源代码中没有,而在FMX与VCL中均实现了,看来确实,FMX与VCL是两个不相干的类库。其次,

cbw2

实现代码是完全一样的:

class PASCALIMPLEMENTATION AxisException : public System::Sysutils::Exception

{

typedef System::Sysutils::Exception inherited;

public:

/* Exception.Create */ inline __fastcall AxisException(const System::UnicodeString Msg) : System::Sysutils::Exception(Msg) { }

/* Exception.CreateFmt */ inline __fastcall AxisException(const System::UnicodeString Msg, System::TVarRec const *Args, const int Args_Size) : System::Sysutils::Exception(Msg, Args, Args_Size) { }

/* Exception.CreateRes */ inline __fastcall AxisException(int Ident)/* overload */ : System::Sysutils::Exception(Ident) { }

/* Exception.CreateResFmt */ inline __fastcall AxisException(int Ident, System::TVarRec const *Args, const int Args_Size)/* overload */ : System::Sysutils::Exception(Ident, Args, Args_Size) { }

/* Exception.CreateHelp */ inline __fastcall AxisException(const System::UnicodeString Msg, int AHelpContext) : System::Sysutils::Exception(Msg, AHelpContext) { }

/* Exception.CreateFmtHelp */ inline __fastcall AxisException(const System::UnicodeString Msg, System::TVarRec const *Args, const int Args_Size, int AHelpContext) : System::Sysutils::Exception(Msg, Args, Args_Size, AHelpContext) { }

/* Exception.CreateResHelp */ inline __fastcall AxisException(int Ident, int AHelpContext)/* overload */ : System::Sysutils::Exception(Ident, AHelpContext) { }

/* Exception.CreateResFmtHelp */ inline __fastcall AxisException(System::PResStringRec ResStringRec, System::TVarRec const *Args, const int Args_Size, int AHelpContext)/* overload */ : System::Sysutils::Exception(ResStringRec, Args, Args_Size, AHelpContext) { }

/* Exception.Destroy */ inline __fastcall virtual ~AxisException(void) { }

};

而所有的9个Exception类,都是实现了构造函数,调用父类System::Sysutils::Exception相应的构造函数进行处理,其次实现了析构函数。所有函数均未做特殊逻辑处理。看来这些Exception类仅是占了个坑,或者是供后续继承使用,不过貌似不太需要,如果是我来用的话,我会直接从System::Sysutils::Exception派生出新的异常处理类的。

cbw3

2) Classes

这么快地完成了Exceptions,感觉还是蛮爽的。再接再励,开始控讨Classes。

cbw4

看起来,这项工作要大得多了,共有126个类。还是找软的捏,貌似TStrings、TStringList与TList最简单了,先干掉这三个。

TStrings定义在System.Classes.hpp中,再一看,该文件共有3240行。干脆是全看过来,过一遍就OK。

嗯,先是定义一堆的枚举类型。感觉很熟悉,以前都用过,很简单的,一次过。

enum TSeekOrigin : unsigned char { soBeginning, soCurrent, soEnd };

typedef System::Word TPlatformIds;

enum TAlignment : unsigned char { taLeftJustify, taRightJustify, taCenter };

typedef TAlignment TLeftRight;

enum TBiDiMode : unsigned char { bdLeftToRight, bdRightToLeft, bdRightToLeftNoAlign, bdRightToLeftReadingOnly };

enum : unsigned char { taAlignTop, taAlignBottom, taVerticalCenter };

typedef TVerticalAlignment TTopBottom;

enum System_Classes__1 : unsigned char { ssShift, ssAlt, ssCtrl, ssLeft, ssRight, ssMiddle, ssDouble, ssTouch, ssPen, ssCommand };

typedef System::Set<System_Classes__1, System_Classes__1::ssShift, System_Classes__1::ssCommand> TShiftState;

typedef int THelpContext;

enum THelpType : unsigned char { htKeyword, htContext };

typedef System::Word TShortCut;

typedef void __fastcall (__closure *TNotifyEvent)(System::TObject* Sender);

typedef void __fastcall (__closure *TGetStrProc)(const System::UnicodeString S);

enum TDuplicates : unsigned char { dupIgnore, dupAccept, dupError };

下来,是N个异常处理类,整个结构层次如下:

EStreamError

> EFileStreamError

> EFCreateError

> EFOpenError

> EFilerError

> EReadError

> EWriteError

> EClassNotFound

> EMethodNotFound

> EInvalidImage

EResNotFound

EListError

EBitsError

EStringListError

EComponentError

EParserError

EInvalidOperation

EOutOfResources

这些异常处理类,也无需特别关注。

下来碰到一个以前用得较少的东东:

typedef System::DynamicArray<void *> TPointerList;

看名字是动态数组,是什么含义呢。说实在的,以前对这块研究还比较少。还是上网搜索一下具体用法哈

C++Builder里面有动态数组System::DynamicArray,使用如下:

//==============================================

//数组长度

DynamicArray<int> arrayOfInt;

arrayOfInt.Length = 10;

cout << "ArrayLength: " << arrayOfInt.Length << endl;

//==============================================

释放数组,只有把长度设置为0即可,不可使用delete删去:

//==============================================

arrayOfInt.Length = 0;

//==============================================

访问数据:

void InitArray(DynamicArray<char> &c_array)

{

c_array[0] = 'A';

c_array[1] = 'B';

cout << "Third char is: " << c_array[2];

}

//==============================================

Low和 High 属性表示数组的上下边界

例如数组求和的函数:

int TotalArray(const DynamicArray<int>& arrayOfInt)

{

int total=0;

for (int i=arrayOfInt.Low; i<=arrayOfInt.High; i++)

total += arrayOfInt[i];

return total;

}

当然也可以这样:

for (int i=0; i<arrayOfInt.Length; i++)

{

total += arrayOfInt[i];

}

//==================================================

赋值,比较和复制动态数组:

Dynamic Arrays are reference counted. When a DynamicArray is assigned to another, only the reference is assigned (and the reference count adjusted), the content of the source is not copied. Similarly, when two Dynamic Arrays are compared, only the references are compared, not the contents. To copy the contents of a DynamicArray, you must use the Copy (or CopyRange) methods.

//C++ example

void foo(DynamicArray<int> &i_array)

{

DynamicArray<int> temp = i_array;//此处是引用赋值,不复制数据

assert(temp == i_array); // temp 和i_array 指向同一内存数据块

i_array[0] = 20;//此处改变,实际上就是Temp的值

assert(temp[0] == 20); // Temp的值同样也会改变

temp = i_array.Copy(); // 赋值数组,此时temp 和i_array 指向不同内存块,

//但是这两个内存所含数据相同

temp[0] = 10;//此时改变temp的值不会改变i_array的值

assert(temp[0] != i_array[0]); // Above assignment did not

// modify i_array.

}

//=====================================================

Multidimensional dynamic arrays(多维数组)

例如2维数组,注意该2维数组可以不是方阵数组,

即数组可以由10行,但每一行的元素个数可以不相同

typedef DynamicArray< DynamicArray < AnsiString > > T2DStringArray;

void foo(T2DStringArray &s_array)

{

SetLength(s_array, 10);

for (int i=0; i<s_array.Length; i++)

{ // Set lengths of second dimensions.(NOTE: non-rectangular)

SetLength(s_array[i], i+1);

for (int j=0; j<s_array[i].Length; j++)

s_array[i][j] = itoa(i*10+j);

}

}

//=====================================================

哦,大概理解了。继续看下去。

再往下是有关于TList的,TListSortCompareFunc接口、TListEnumerator枚举器、TList。

唉,看了正规军的源代码,发现自己以前所用的东东真是弱爆了。如果让我来实现TList,我或许就用vector了,今天算是学会了用DynamicArray。另外,好象是第一次看到__classmethod这个修饰关键字,应该表示类方法的意思吧。

还看到一个有趣的现象,就是通过TList删除其某个子对象时,会调用Notify函数,结果这个函数啥也没做。

晕哈,回过头一看,Notify是个虚函数,可以在派生类中实现相应的处理逻辑。这与Windows消息机制实现方式类似,在合适的时机调用合适的函数。

还有一点没看明白,在TList.Add、Delete、Insert等函数中,均有一个判断:if ClassType <> TList then…,这是嘛意思?在TList类中函数,ClassType应该就是TList的哈?难道会不一样?哦,确实是自己的问题,这是个很简单的问题,还是派生情况,在子类中ClassType就不会是TList的了,届时会调用子类的Notify函数进行相应处理。

嗯,还是有收获的,如果以后自己编个程序会用到派生于TList的类时,可以关注于Notify函数,貌似能取得某些信息。

要不就编个程序来试试。

先放一个TMemo,再放TSpeedButton,新的IDE还是有些不习惯哈,直接双击或拖动TSpeedButton到窗口上时,居然不见了。在对象浏览器中可以看到,居然还无法删除。最后在structure视图中才删除掉。想了一会才明白,直接放在父容器中去了,还不习惯在Memo中还有控件。

cbw5

现在有点感觉,在FireMonkey中,容器无所不在,好象在哪里看到过,连其中的线都可以成为容器。太夸张了哈。

头文件:

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

#ifndef MainUnit1H

#define MainUnit1H

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

#include <FMX.Controls.hpp>

#include <FMX.Layouts.hpp>

#include <FMX.Memo.hpp>

#include <FMX.Types.hpp>

#include <System.Classes.hpp>

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

class TMyList : public TList

{

public:

__fastcall TMyList() {}

virtual void __fastcall Notify(void * Ptr, TListNotification Action);

};

class TForm1 : public TForm

{

__published: // IDE-managed Components

TSpeedButton *SpeedButton1;

TSpeedButton *SpeedButton2;

TMemo *Memo1;

void __fastcall FormDestroy(TObject *Sender);

void __fastcall SpeedButton1Click(TObject *Sender);

void __fastcall SpeedButton2Click(TObject *Sender);

private: // User declarations

TMyList * FList;

public: // User declarations

__fastcall TForm1(TComponent* Owner);

void __fastcall AddLog(AnsiString info);

};

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

extern PACKAGE TForm1 *Form1;

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

#endif

源文件:

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

#include <fmx.h>

#pragma hdrstop

#include "MainUnit1.h"

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

#pragma package(smart_init)

#pragma resource "*.fmx"

TForm1 *Form1;

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

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

FList = new TMyList;

}

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

void __fastcall TForm1::FormDestroy(TObject *Sender)

{

delete FList;

}

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

void __fastcall TForm1::AddLog(AnsiString info)

{

Memo1->Lines->Add(info);

}

void __fastcall TMyList::Notify(void * Ptr, TListNotification Action)

{

AnsiString type = Action == lnAdded ? "添加" : Action == lnExtracted ? "提取" : Action == lnDeleted ? "删除" : "";

Form1->AddLog(Format("%s子对象 0x%X, 现有子对象 %d 个", ARRAYOFCONST((type.c_str(), int(Ptr), Count))));

}

void __fastcall TForm1::SpeedButton1Click(TObject *Sender)

{

FList->Add(this);

}

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

void __fastcall TForm1::SpeedButton2Click(TObject *Sender)

{

if(FList->Count)

FList->Delete(0);

}

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

运行结果:

cbw6

呵呵,这个功能,或许在CB6中就实现了,但一直没用过,今天赚到了!

在此基础上,再看其它与List相关的就容易多了,象TThreadList,其中就是一个TList *数据成员,然后通过TMonitor::Enter与TMonitor::Exit来确保无冲突访问。嗯,这也是今天的一个收获,之前编程一般采用Windows内核对象来进行同步等操作,原来TMonitor类可以直接如此使用。

再下来是接口列表TInterfaceList,这个看起来貌似比较高难度,其实也简单。它与TList类似,只不过是把void *换成接口类型System::_di_IInterface了。

原文地址:https://www.cnblogs.com/drgraph/p/2343307.html