C++Builder 对C++的扩展
C++Builder完全兼容标准C++,标准C++是一个大而广泛的类和函数的集合,这个标准由国际标准化组织(ISO)与美国国家标准委员会(ANSI)共同指定。此标准具有广泛的权威性,一般的开发工具都完全支持它。C++Builder包含了C++,同时又扩展了C++。它在以下几方面增强了C++。
3.4.1 动态函数
动态函数是C++Builder所特有的,它仅仅用在由TObject派生的类中,它是专门为VCL类库而引入的。动态函数和前面所讲的虚函数(virtual functions)是类似的,惟一不同的是虚函数不但在它被定义的类的对象的虚方法表中占有一定的存储空间,在该类的派生类的对象的虚方法表中也同样占有存储空间;动态函数仅仅在它被定义的类的对象的虚方法表中占据一定空间,而在派生类对象中则没有。如果调用一个动态函数,可是又没有在对象中定义它,那么编译器将向上搜索它的父类的虚方法表,直到搜索到为止。动态函数的定义也与虚函数类似,将虚函数声明中的virtual关键字替换成_declspec(dynamic)即可。(派生类没有,编译器会往上搜索父类)
根据上面的论述,可以推出动态函数降低了虚方法表的大小,但是带来的负面效应是增加了搜索函数地址控制的时间。
值得注意的是动态函数仅仅在TObject的后继派生类中可用,所以如果在一个普通类中使用了它将会产生一个错误。
另外,虚函数和动态函数虽然类似,但是它们不能相互转换。也就是说虚函数不能重新声明为动态函数,同样,动态函数也不能重新声明为虚函数。
3.4.2 #pragma package指令
#pragma package指令,这是C++Builder新添的编译预处理指令,它确保各个封装的单元按照它们的依赖关系所确定的顺序初始化。包(package)源文件默认包含这条预编译指令。典型的用法是在用作建立包的.cpp源程序中加入卸#pragmapackage。
这个#pragma影响编译单元的初始化顺序,单元按照下述顺序初始化:
l它们之间的使用关系,也就是说,如果单元1依赖单元2,那么单元2必须在单元1之前初始化。
l连接的顺序。
l单元内的优先顺序。
对于普通的.obj文件(那些不用来建立单元的),初始化时首先根据优先顺序,然后再是连接顺序。改变.obj的连接顺序也就改变全局对象的构造函数的调用顺序。
3.4.3 #pragma hdrstop指令
表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。
有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragma startup指定编译优先级,如果使用了#pragmapackage(smart_init) ,BCB就会根据优先级的大小先后编译。
#pragma resource "*.dfm"表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体外观的定义。
3.4.3为异常处理增加了try/_finally
try/finally结构是C++Builder所特有的,_finally的句法是:
try{} __finally{}是出不出现异常都做__finally里的动作!
try
{
,.~
}
_finally
{
}
-----------------------------------------------------------------------------
try...catch是标准C++
try...except和try...finally是BCB中的.
我一般是这样用的:
try
{
...//变量初始
try
{
...//执行函数功能
}
__finally
{
...//释放资源
}
return//函数返回值
}
catch(Exception &E)
{
...//处理异常
}
-------------------------------------------------------
class MyException{
public:AnsiString iMessage;
MyException(AnsiString Message) { iMessage=Message;
}};
throw new MyException(“Test Exception Message”);
----------------------------------------------------------
标准委员会为我们定义了try {/* code */} catch (...) {/* code */ }机制,跟异常机制一样,它完全可以定制来满足您的需要!只需把您的执行代码段放在try模块中就行了,您还需要一个catch( ) 或 __finally 模块来告诉程序(如果)得到一个异常的时候作什么。现在就是你这么做的好处,你定义了一个类class类型并且输入变量来捕捉异常-通过声明catch( )。(在前面的例子中,应该是这样-catch(MyException &E) { /*在这里书写捕捉到异常后的处理代码*/})为了让这个系统更有力,你可以建立完整的子类继承树。这样当你捕捉基类时你可以捕捉所有从这个基类继承的异常类型(VCL中一个很好的例子就是所有的异常都是从Exception类继承而来的,所以catch(Exception& E) 将捕捉所有的VCL异常,当然包也括您所产生的。但EsocketError除外
使用一个
__finally{
}
模块
,
你可以指定不管有否异常产生都将运行的
代码。这里是清除你通过
new
方法分配的局部变量及将所有应该设定回正常状态的标志复
位(例如将一个等待状态的鼠标指针复位成正常状态)的最方便的地方
使用一个 __finally{ } 模块,你可以 指定不管有否异常产生都将运行的代码 。这里是清除你通过new方法分配的局部变量及将所有应该设定回正常状态的标志复位(例如将一个等待状态的鼠标指针复位成正常状态)的最方便的地方
-------------------------------------------------------------------------------------------------------
3.4.4新增加的关键宇
C++Builder为C+十增加了许多关键字,以适应其快速应用开发(RAD)环境。包括两
个类范围关键字以及自动Get/Set指令的支持。
1.新的类范围
从前面的介绍,我们知道类中包含三个类成员访问说明,分别是public、private和
protected。C++Builder定义了两个新的对类的访问说明,他们是published和automated。
_published范围限定词允许C++Builder在设计期间访问组件的属性,这个新的访问限制
允许与public相同的访问权限。用published限制的类成员在运行期间是可用的(就像public类成员一样),而且设计期间也是可用的。这就是为什么在C++Builder对象查看器中可以设置组件属性的原因。在C什Builder窗体中加入的组件都会自动~_published中声明。
新建一个工程,随便在窗体上加入几个组件,然后切换到代码编辑窗口中,在Unitl.cpp
中选择快捷菜单中的OpenSomce/Headerfile命令,切换到Unitl.h文件中,我们可以看到
如下所示的类的声明:
classTForml:public TForm
{
_published:
TButton*Buttonl;
TLabel *Labell
TEdit*Editl
private:
public:
fastcall TForml(Tcomponent *Owner);
可以看出,在窗体中加入的组件都在published段中声明。
如果需要向一个窗体加入成员变量或方法,那么应该private或public段中加入,而不
应该放在published段。一般情况下,不能手工修改窗体类的published段,所有带声明的
组件都会对应于窗体的DFM文件,因此手工修改可能造成两个文件的不匹配。
autometed与public或published具有相同的访问权限,不同之处是,它用于创建类的OLE
信息。通常用于创建OLEAutomationServers;当在C++Builder中建立OLEAutomationServers
时,编译器会为成员函数及属性产生OLEAutomation信息,并声明在autometed段中。
2.Get/Set指令
除了数据成员和方法之外,C十+Builder中的类还可以包含属性。通过在对象查看器中
设置属性值了解属性的含义,其实它还有更为广泛的用途。
属性与类成员,特别是私有成员有着密切的联系。属性提供了一种信息隐藏的机制。
属性是通过Get/Set指令来实现的。要访问每个私有类成员,可以编写一个指令去获取(Get)
值,另一个指令去设置(Set)值,这就是所谓的Get/Set指令。因为并没有直接访问类的
私有部分,所以这种方法能提供良好的信息掩蔽,而且以后还能随意改变内部的数据形式。
可以像一个简单变量一样来访问属性。
3.fastcall
在C++Builder的窗体方法中自动产生fastcall,这是编译器指示方法参数通过寄存器
传输,而不是通过堆栈。这是所有窗体类方法所必须的。然而,如果加入自定义的方法也
【C++Builder对C++的扩展】 需要遵循这一要求。