下载 第9 章VCL 的C++ 语言支持 C + + B u i l d e r 的快速应用程序开发(R A D )能力是建立在用Object Pascal 编写的可视组件库(V C L ) 基础之上的。本章说明Object Pascal 语言的特征、结构及概念如何在C + + B u i l d e r 中实现以支持VCL 。 本章的第一部分比较C++ 和Object Pascal 的对象模型, 并说明C++Builder 如何组合这两种方法。本 章的第二部分说明Object Pascal 语言的结构如何对应转换成C++Builder 中的C + +结构。包括一些被增加 来支持VCL 的关键字的扩展的相关细节。这些扩展,如闭合和属性, 是独立的支持基于VCL 的代码的有 用特征。 注意从TObject 派生的C + +类是指那些TObject 是其最初的、然而并非直接的祖先的类。为保 持编译器逻辑上的一致性,这样的类也被称为“VCL 风格类”。 9.1 C++ 和Object Pascal 对象模型 C++ 和Object Pascal 在创建、初始化、引用、拷贝和销毁对象的方法上有些微小的差异。在本节中 描述这些细微的差别和它们对C++Builder VCL 风格类的影响。 9.1.1 对象本身和实例 在C + +中,类的一个实例是一个实际的对象。那个对象能直接被操作,或者通过引用或指针间接访 问它。例如,给定一个构造函数中没有参数的C++ 类CPP_class, 下列变量都是该类的有效实例变量: 相反,在Object Pascal 中,一个O b j e c t 类型的变量总是间接地引用对象。所有对象的内存都动态地 被分配。例如, 给定Object Pascal 类O P _ c l a s s : ref 是OP_class 类型的对象的一个“引用”。转换到C++Builder 代码, 将是: 1. 区分C++ 和Object Pascal 的引用 文档中经常会把Object Pascal 类实例变量作为引用提及, 但却作为指针来描述它的行为。这是因为它 兼有这两者的属性。一个Object Pascal 引用类似C++ 指针,但有下列的不同: • 一个Object Pascal 引用是隐式的间接引用(在此情况下更像一个C++ 引用)。 • 一个Object Pascal 引用不像定义的操作那样有指针运算。 Object Pascal 引用和C++ 引用比较时,也有类似和不同之处。两种语言的引用都是隐式的间接引用, 然而, • 一个Object Pascal 引用可以被重指, 而C++ 引用不能。 • 一个Object Pascal 引用可以是nil, 而C++ 引用必须指向有效的对象。 有些V C L 结构下的设计计划是建立在使用这种类型的实例变量的基础上的。指针是最接近O b j e c t P a s c a l 引用的C + +语言结构。因此, 几乎所有的VCL 对象的标识符在C + + B u i l d e r 中都被转换为C + +指针。
注意Object Pascal 的var 参数类型最接近C++ 的引用。参见9 . 2 . 3 节的“Va r 参数”可获得更多 信息。 2. 拷贝对象 与C + +不同,Object Pascal 没有可支持拷贝对象的内嵌编译器。本节描述这个差别对VCL 风格类赋 值操作符和拷贝构造函数的影响。 ( 1 )赋值操作符 Object Pascal 赋值操作符(: =)不是一个类赋值操作符(o p e r a t o r =())。操作符赋值拷贝引用,而不 是对象。在下列代码中,B 和C 都指向同一个对象: 这个例子在C++Builder 中转换为下列代码: C++Builder 的VCL 风格类的赋值操作符遵循Object Pascal 语言的规定。这意味着,下列代码中,在 两个dereferenced 指针之间的赋值是无效的,因为它们试图拷贝对象而不是指针: 注意对于VCL 风格类,使用C + +语法的引用是有效的。例如, 下列代码是有效的: 尽管与使用赋值操作符不同,但对于澄清和比较而言,这里提出的语法已经足够类似了。 ( 2 )拷贝构造函数 Object Pascal 没有内嵌的拷贝构造函数。因而, 在C + + B u i l d e r 中的V C L 风格类也没有内嵌的拷贝构造 函数。下例中的代码试图使用一个拷贝构造函数创建TButton 指针: 对于V C L 类,不能编写依赖于一个内嵌的拷贝构造函数的代码。要在C + + B u i l d e r 中创建V C L 风格类 对象的一个拷贝, 可编写一个成员函数以拷贝对象。另外, VCL TPersistent 类的派生类可重载A s s i g n 方法 以从一个对象拷贝数据到另一个对象。例如,对于包含资源图像的图形类,诸如TBitmap 和T I c o n 通常就 会这么做。拷贝一个对象的方式最终由程序员(组件开发者)决定;但需注意一些标准C++ 使用的拷贝 方法对V C L 风格类是不适用的。 3. 对象作为函数参数 正如前面所讨论的,C + +和Object Pascal 中的实例变量不是等同的。在将对象作为函数的参数传递时 应该记住这一点。在C + +中, 对象可以通过值、引用或指针传递给函数。在Object Pascal 中,当一个对象按 值传递给函数时,应记住这个对象参数已经是一个对象的引用了。所以,实际上是引用被按值传递,而 不是实际的对象。在Object Pascal 中,不能像在C + +中一样将实际对象按值传递。VCL 风格类对象在传 递给函数时遵循Object Pascal 的规定。 9.1.2 C++Builder 中V C L 类的对象构造 C++ 和Object Pascal 构造对象是不同的。本节概述这一问题并说明C + + B u i l d e r 如何综合这两种方式。 132 计计第一部分使用C++Builder 编程 下载
1. C++ 对象构造 在标准的C + +中,构造的顺序先是虚基类, 然后是基类, 最后是派生类。C++ 语法使用构造函数初始 化列表调用基类构造函数。对象的运行时类型为当前构造函数被调用的类的类型。虚拟方法的分派遵循 对象的运行时类型并因此在构造期间变化。 2. Object Pascal 对象构造 在Object Pascal 中,仅有实例化的类的构造函数确保被调用,然而, 仍为基类分配内存。直接基类的 构造通过在相应的派生类的构造函数中调用i n h e r i t e d 来进行。习惯上,V C L 类使用i n h e r i t e d 调用(非空) 基类构造函数。不过, 这并不是语言的要求。对象的运行时类型立即被建立为实例化的类的类型,并且不 在基类构造函数被调用时变化。虚拟方法的分派遵循对象的运行时类型并且不在构造期间变化。 3. C++Builder 对象构造 VCL 风格对象的构造与Object Pascal 对象类似, 但适用C++ 语法。这意味着调用基类构造函数时遵循 C + +语法,对于所有的非V C L 的基类和最直接的V C L 父类使用初始化列表。这个V C L 基类最先被构造。它 使用inherited 构造自己的基类,遵循Object Pascal 的方法。因此,VCL 基类构造的顺序与C++的相反。然后 从最远的祖先到派生类,所有的C++ 基类被构造。对象的运行时类型和虚拟方法分派也基于Object Pascal 。 图9 - 1 说明了一个VCL 风格类实例的构造, MyDerived 从M y B a s e 派生, MyBase 是T WinControl 的一个 直接的派生类。MyDerived 和MyBase 以C++ 实现。T WinControl 是以Object Pascal 实现的V C L 类。 图9-1 VCL 风格类对象的构造顺序 第9 章VCL 的C++语言支持计计133 下载 继承性构造顺序 构造函数调用 inherited 构造函数调用 inherited 没有构造函数 空的构造函数 分界
注意到对一个C++ 程序员来说,构造的顺序似乎是反的,因为对于实际的VCL 类,它从最边缘的 父类开始一直到TO b j e c t ,然后构造M y B a s e ,最后构造派生类。 注意TComponent 不调用i n h e r i t e d ,因为TPersistent 没有构造函数。TObject 有一个空的构造 函数, 它也不被调用。若这些类构造函数被调用,其顺序将遵循图9 - 1 中的顺序(这些类为图中 带灰影的部分)。 表9 - 1 总结了C + +、Object Pascal 、C + + B u i l d e r 的对象构造模型: 表9-1 对象模型比较 C + + Object Pascal C + + B u i l d e r 构造顺序 虚基类,基类,最后为派生类 调用基类构造函数的方法 自动地,从构造函数初始化表 当被构造时对象的运行时类型 变化,对应于当前构造类的类型 虚拟方法的分派 在基类构造函数被调用时根据对 象的运行时类型变化 9.1.3 在基类构造函数调用虚拟方法 虚拟方法在V C L 基类构造函数的函数体内被调用,也就是说,类的实现以Object Pascal 模式, 分派则 以C + +模式,取决于对象的运行时类型。因为C++Builder 综合了Object Pascal 模式的立即设置运行时对象 类型,以及C + +模式的在派生类构造前构造基类,从V C L 风格类的基类构造函数调用虚拟方法会有一些 副作用。这些影响在下面描述,并且以至少有一个父类的实例化类为例说明。这里,这个实例化类被作 为一个派生类。 1. Object Pascal 模型 在Object Pascal 中,程序员可使用i n h e r i t e d 关键字, 它提供了一种灵活的方式在一个派生类的构造函 数体内任意位置调用基类构造函数。因而, 若派生类根据建立的对象重载任何虚拟方法或初始化数据成 员, 可在基类构造函数和虚拟方法被调用前发生。 2. C++ 模型 C++ 语法没有i n h e r i t e d 关键字可在派生类的构造函数体内任意位置调用基类构造函数。对于C++ 模 型,使用i n h e r i t e d 关键字是不必要的,因为对象的运行时类型是当前被构造类的类型,而不是派生类。因 此, 虚拟方法的调用是当前的类而不是派生类。因而, 在这些方法被调用以前初始化数据成员或建立派生 类的对象也是不必要的。 3. C++Builder 模型 在C + + B u i l d e r 中,VCL 风格对象的运行时类型,为派生类的类型,并在调用基类构造函数期间不变。 因此, 如果基类构造函数调用一个虚拟的方法,当派生类重载它时,派生类的方法被调用。如果这个虚拟 方法依赖于派生类构造函数体或初始化列表中的任何东西,方法在这发生以前被调用。例如, 134 计计第一部分使用C++Builder 编程 下载 实例化类的构造函数是第一个也 是唯一一个被自动调用的构造函数。 若其后的类被构造,构造顺序为从 最边缘到根 选择性地、明确地在派在类构造 函数期间的任何时候,通过使用 i n h e r i t e d 关键字 马上建立为实例化类的类型 遵循运行时对象类型,它在所有 的类构造函数调用期间不变 最直接的VCL 基类, 然后构造 遵循Object Pascal 模型,再接下来 构造遵循C + +模型(除非不允许虚 基类) 自动地从构造函数初始化生列 表的最直接的父类的V C L 基类构 造函数。然后遵循Object Pascal 方法,使用i n h e r i t e d 调用构造函数 马上建立为实例化类的类型 遵循运行时对象类型,它在所 有的类构造函数调用期间不变
本人现在的开发工具是VC,但想用用C++ Builder 和 Delphi
想学就来点不完全同的呀。
第9 章VCL 的C++ 语言支持
C + + B u i l d e r 的快速应用程序开发(R A D )能力是建立在用Object Pascal 编写的可视组件库(V C L )
基础之上的。本章说明Object Pascal 语言的特征、结构及概念如何在C + + B u i l d e r 中实现以支持VCL 。
本章的第一部分比较C++ 和Object Pascal 的对象模型, 并说明C++Builder 如何组合这两种方法。本
章的第二部分说明Object Pascal 语言的结构如何对应转换成C++Builder 中的C + +结构。包括一些被增加
来支持VCL 的关键字的扩展的相关细节。这些扩展,如闭合和属性, 是独立的支持基于VCL 的代码的有
用特征。
注意从TObject 派生的C + +类是指那些TObject 是其最初的、然而并非直接的祖先的类。为保
持编译器逻辑上的一致性,这样的类也被称为“VCL 风格类”。
9.1 C++ 和Object Pascal 对象模型
C++ 和Object Pascal 在创建、初始化、引用、拷贝和销毁对象的方法上有些微小的差异。在本节中
描述这些细微的差别和它们对C++Builder VCL 风格类的影响。
9.1.1 对象本身和实例
在C + +中,类的一个实例是一个实际的对象。那个对象能直接被操作,或者通过引用或指针间接访
问它。例如,给定一个构造函数中没有参数的C++ 类CPP_class, 下列变量都是该类的有效实例变量:
相反,在Object Pascal 中,一个O b j e c t 类型的变量总是间接地引用对象。所有对象的内存都动态地
被分配。例如, 给定Object Pascal 类O P _ c l a s s :
ref 是OP_class 类型的对象的一个“引用”。转换到C++Builder 代码, 将是:
1. 区分C++ 和Object Pascal 的引用
文档中经常会把Object Pascal 类实例变量作为引用提及, 但却作为指针来描述它的行为。这是因为它
兼有这两者的属性。一个Object Pascal 引用类似C++ 指针,但有下列的不同:
• 一个Object Pascal 引用是隐式的间接引用(在此情况下更像一个C++ 引用)。
• 一个Object Pascal 引用不像定义的操作那样有指针运算。
Object Pascal 引用和C++ 引用比较时,也有类似和不同之处。两种语言的引用都是隐式的间接引用,
然而,
• 一个Object Pascal 引用可以被重指, 而C++ 引用不能。
• 一个Object Pascal 引用可以是nil, 而C++ 引用必须指向有效的对象。
有些V C L 结构下的设计计划是建立在使用这种类型的实例变量的基础上的。指针是最接近O b j e c t
P a s c a l 引用的C + +语言结构。因此, 几乎所有的VCL 对象的标识符在C + + B u i l d e r 中都被转换为C + +指针。
信息。
2. 拷贝对象
与C + +不同,Object Pascal 没有可支持拷贝对象的内嵌编译器。本节描述这个差别对VCL 风格类赋
值操作符和拷贝构造函数的影响。
( 1 )赋值操作符
Object Pascal 赋值操作符(: =)不是一个类赋值操作符(o p e r a t o r =())。操作符赋值拷贝引用,而不
是对象。在下列代码中,B 和C 都指向同一个对象:
这个例子在C++Builder 中转换为下列代码:
C++Builder 的VCL 风格类的赋值操作符遵循Object Pascal 语言的规定。这意味着,下列代码中,在
两个dereferenced 指针之间的赋值是无效的,因为它们试图拷贝对象而不是指针:
注意对于VCL 风格类,使用C + +语法的引用是有效的。例如, 下列代码是有效的:
尽管与使用赋值操作符不同,但对于澄清和比较而言,这里提出的语法已经足够类似了。
( 2 )拷贝构造函数
Object Pascal 没有内嵌的拷贝构造函数。因而, 在C + + B u i l d e r 中的V C L 风格类也没有内嵌的拷贝构造
函数。下例中的代码试图使用一个拷贝构造函数创建TButton 指针:
对于V C L 类,不能编写依赖于一个内嵌的拷贝构造函数的代码。要在C + + B u i l d e r 中创建V C L 风格类
对象的一个拷贝, 可编写一个成员函数以拷贝对象。另外, VCL TPersistent 类的派生类可重载A s s i g n 方法
以从一个对象拷贝数据到另一个对象。例如,对于包含资源图像的图形类,诸如TBitmap 和T I c o n 通常就
会这么做。拷贝一个对象的方式最终由程序员(组件开发者)决定;但需注意一些标准C++ 使用的拷贝
方法对V C L 风格类是不适用的。
3. 对象作为函数参数
正如前面所讨论的,C + +和Object Pascal 中的实例变量不是等同的。在将对象作为函数的参数传递时
应该记住这一点。在C + +中, 对象可以通过值、引用或指针传递给函数。在Object Pascal 中,当一个对象按
值传递给函数时,应记住这个对象参数已经是一个对象的引用了。所以,实际上是引用被按值传递,而
不是实际的对象。在Object Pascal 中,不能像在C + +中一样将实际对象按值传递。VCL 风格类对象在传
递给函数时遵循Object Pascal 的规定。
9.1.2 C++Builder 中V C L 类的对象构造
C++ 和Object Pascal 构造对象是不同的。本节概述这一问题并说明C + + B u i l d e r 如何综合这两种方式。
132 计计第一部分使用C++Builder 编程
下载
在标准的C + +中,构造的顺序先是虚基类, 然后是基类, 最后是派生类。C++ 语法使用构造函数初始
化列表调用基类构造函数。对象的运行时类型为当前构造函数被调用的类的类型。虚拟方法的分派遵循
对象的运行时类型并因此在构造期间变化。
2. Object Pascal 对象构造
在Object Pascal 中,仅有实例化的类的构造函数确保被调用,然而, 仍为基类分配内存。直接基类的
构造通过在相应的派生类的构造函数中调用i n h e r i t e d 来进行。习惯上,V C L 类使用i n h e r i t e d 调用(非空)
基类构造函数。不过, 这并不是语言的要求。对象的运行时类型立即被建立为实例化的类的类型,并且不
在基类构造函数被调用时变化。虚拟方法的分派遵循对象的运行时类型并且不在构造期间变化。
3. C++Builder 对象构造
VCL 风格对象的构造与Object Pascal 对象类似, 但适用C++ 语法。这意味着调用基类构造函数时遵循
C + +语法,对于所有的非V C L 的基类和最直接的V C L 父类使用初始化列表。这个V C L 基类最先被构造。它
使用inherited 构造自己的基类,遵循Object Pascal 的方法。因此,VCL 基类构造的顺序与C++的相反。然后
从最远的祖先到派生类,所有的C++ 基类被构造。对象的运行时类型和虚拟方法分派也基于Object Pascal 。
图9 - 1 说明了一个VCL 风格类实例的构造, MyDerived 从M y B a s e 派生, MyBase 是T WinControl 的一个
直接的派生类。MyDerived 和MyBase 以C++ 实现。T WinControl 是以Object Pascal 实现的V C L 类。
图9-1 VCL 风格类对象的构造顺序
第9 章VCL 的C++语言支持计计133 下载
继承性构造顺序
构造函数调用
inherited
构造函数调用
inherited
没有构造函数
空的构造函数
分界
父类开始一直到TO b j e c t ,然后构造M y B a s e ,最后构造派生类。
注意TComponent 不调用i n h e r i t e d ,因为TPersistent 没有构造函数。TObject 有一个空的构造
函数, 它也不被调用。若这些类构造函数被调用,其顺序将遵循图9 - 1 中的顺序(这些类为图中
带灰影的部分)。
表9 - 1 总结了C + +、Object Pascal 、C + + B u i l d e r 的对象构造模型:
表9-1 对象模型比较
C + + Object Pascal C + + B u i l d e r
构造顺序
虚基类,基类,最后为派生类
调用基类构造函数的方法
自动地,从构造函数初始化表
当被构造时对象的运行时类型
变化,对应于当前构造类的类型
虚拟方法的分派
在基类构造函数被调用时根据对
象的运行时类型变化
9.1.3 在基类构造函数调用虚拟方法
虚拟方法在V C L 基类构造函数的函数体内被调用,也就是说,类的实现以Object Pascal 模式, 分派则
以C + +模式,取决于对象的运行时类型。因为C++Builder 综合了Object Pascal 模式的立即设置运行时对象
类型,以及C + +模式的在派生类构造前构造基类,从V C L 风格类的基类构造函数调用虚拟方法会有一些
副作用。这些影响在下面描述,并且以至少有一个父类的实例化类为例说明。这里,这个实例化类被作
为一个派生类。
1. Object Pascal 模型
在Object Pascal 中,程序员可使用i n h e r i t e d 关键字, 它提供了一种灵活的方式在一个派生类的构造函
数体内任意位置调用基类构造函数。因而, 若派生类根据建立的对象重载任何虚拟方法或初始化数据成
员, 可在基类构造函数和虚拟方法被调用前发生。
2. C++ 模型
C++ 语法没有i n h e r i t e d 关键字可在派生类的构造函数体内任意位置调用基类构造函数。对于C++ 模
型,使用i n h e r i t e d 关键字是不必要的,因为对象的运行时类型是当前被构造类的类型,而不是派生类。因
此, 虚拟方法的调用是当前的类而不是派生类。因而, 在这些方法被调用以前初始化数据成员或建立派生
类的对象也是不必要的。
3. C++Builder 模型
在C + + B u i l d e r 中,VCL 风格对象的运行时类型,为派生类的类型,并在调用基类构造函数期间不变。
因此, 如果基类构造函数调用一个虚拟的方法,当派生类重载它时,派生类的方法被调用。如果这个虚拟
方法依赖于派生类构造函数体或初始化列表中的任何东西,方法在这发生以前被调用。例如,
134 计计第一部分使用C++Builder 编程
下载
实例化类的构造函数是第一个也
是唯一一个被自动调用的构造函数。
若其后的类被构造,构造顺序为从
最边缘到根
选择性地、明确地在派在类构造
函数期间的任何时候,通过使用
i n h e r i t e d 关键字
马上建立为实例化类的类型
遵循运行时对象类型,它在所有
的类构造函数调用期间不变
最直接的VCL 基类, 然后构造
遵循Object Pascal 模型,再接下来
构造遵循C + +模型(除非不允许虚
基类)
自动地从构造函数初始化生列
表的最直接的父类的V C L 基类构
造函数。然后遵循Object Pascal
方法,使用i n h e r i t e d 调用构造函数
马上建立为实例化类的类型
遵循运行时对象类型,它在所
有的类构造函数调用期间不变
http://cn.ilike.lycosasia.com/program/book/index.html
分析你的具体情况可得出以下结论:
先学CB---------因为你熟悉c++
再学delphi-----delphi和cb得最大区别就是小小的语法问题,学好其一,很容易上手其二!
为什么两样都要学呢?
1。找工作成功率增加100%
2。老板的需要