目录

  • Delphi永远没办法在栈上创建一个对象
  • Delphi的构造函数更象是个类方法(静态成员函数)
  • Delphi的析构函数中可以调用纯虚方法
  • Delphi在构造对象时自动将成员变量清零
  • Delphi构造函数中抛出异常会自动先调用析构函数
  • Delphi简化了COM接口的AddRef、Release和QueryInterface

一、Delphi永远没办法在栈上创建一个对象

下面是一段常见的的Delphi代码,在过程的开头声明本过程所需要的全部局部变量:

procedure Foo;
var
obj: TObject; //这句容易被C++程序员误会。
begin
...
end;

C++程序员会以为obj这个变量就是TObject对象实例本身,会以为这一句是在栈上声明并构造了TObject类的一个对象实例,他们会与下面的C++代码混淆:

void Foo() {

CObject obj; //这一句的确在栈上构造了CObject类的
... //一个对象实例,并且将在离开Foo函数时自动析构它
}

牢记一点,在Delphi里,永远不可能在栈上构造一个对象,也永远不可能对一个对象进行值传递,程序员能看到的是“指向对象实例的指针”,简单地说“一切皆指针”,上例中obj其实就是一个“TObject类型的指针”,当它在栈上被声明的时候,它的值不可知(与C++一样),也没有任何对象被构造出来。上述代码翻译成C++,基本上就是:

void Foo() {
CObject * obj; // 声明一个CObject类型的指针
// 但没有任何对象被构造或与之关联
...
}

作为一个佐证,在Delphi里,sizeof(TObject), sizeof(Self), sizeof(obj) 结果都是4,即一个32位指针的大小。

二、Delphi的构造函数更象是个类方法(静态成员函数)

由于Delphi不允许在栈上构造对象,那么对象实例就只能创建在堆上,Delphi没有new关键字(倒有一个名为New的procedure),而是用一种有别于C++的语法来(在堆上)构造对象:

procedure Foo;
var
obj: TObject; //obj本质上只是一个TObject类型的指针
begin
obj := TObject.Create; //在堆上构造一个TObject对象实例并将其地址赋值给obj
obj.Free; //令obj指向的对象析构
end;

与C++一样,在堆上构造的函数不会在离开作用域的时候被自动析构,所以在离开Foo这个过程之些,要调用TObject的Free方法来析构它。Free方法会调用Destroy析构函数,只不过在调用Destroy之前会判断Self是否为空,如果为空就直接返回。Delphi里的Self,就是C++里的this。

Delphi是单根继承,所有类都从TObject派生而来,而所有类的构造函数一定名为Create,而析构函数一定名为Destroy,当然,析构函数肯定是虚函数。

从声明的形式上看,Create方法象是一个成员函数,但从使用上看,它更象一个类方法(C++里叫静态成员函数),因为调用它的时候,限定名不是对象,而是类名(Txxxxx.Create)。

三、Delphi的析构函数中可以调用纯虚方法

由于在Delphi的析构函数Destroy里,可以调用任何纯虚函数(在C++里这一点是不可想象的),所以可以认为这个时候,虚方法表有一定未被破坏,那么,如果基类就可以决定析构时一定要调用的函数,哪怕这个函数是个虚函数,甚至纯虚函数。

四、Delphi在构造的时候自动将成员变量清零

任何一个Delphi中的类,当它被构造后,它的所有成员变量被清零,布尔型初始为False,字符串初始为空,整型和浮点型初始化为0……而C++没有这样的保证

五、Delphi构造函数中抛出异常会自动先调用析构函数

Delphi里,如果构造函数中抛出了异常,则会自动先执行析构函数,然后再异常向外抛出;而在C++里,构造函数中若有异常抛出,则析构函数是不会被调用的。

六、Delphi简化了COM接口中的AddRef、Release和QueryInterface

C++里一般用模板对COM接口进行封装,而在Delphi里,AddRef、Release以及QueryInterface都被编译器隐藏掉了,当一个IUnknown类型的变量(本质上也是一个指针)赋值给另一个变量时,编译器在背后自动AddRef,当一个IUnknown变量离开作用域的时候(再也没有人使用它),Release被自动调用,而QueryInterface被抽象为AS运算符:

procedure Foo(const AParam: IUnknown);
var
  bar: IUnknown;
  other: IStream;
begin
  bar := AParam;  //AParam指向的实例由于赋值操作被AddRef一次
  other := bar as IStream; //调用了一次QueryInterface,引用计数再次加一
end; //返回时,other和bar都离开作用域,分别被调用Release各一次

C++中用模板(比如_com_ptr)也可以使引用计数自动化,不过QueryInterface就没那么方便了

七 其它关于构造函数

-----在C++中声明一个对象后编译器会主动调用构造函数,delphi中则需程序员主动调用,这是DELPHI的一个麻烦处,析构个人认为类似。通过FREE进入DESTROY只是因为FREE函数本身的实现就是调用了DESTROY函数。

-----

var
test:TMyClass;

delphi中:这里的test实际是指针(一定要记住);所以必须主动调用构造和析构函数。

-------- 一般自已创建的对象要自已去释放,但对于有owner的控件(调用Create(Owner))可以不用释放,由拥有它的组件释放。

--------

对象还没有创建时其对象指针为nil.可如下判断:
if   test <> nil   then
      调用类函数
------ delphi里所有的类的对象分配全部使用堆分配的方式,而c++里还允许栈分配的方式(MyObject   obj;),使用栈分配的方式时(比如函数中的局部变量)在生存期结束时,会自动调用析构函数进行释放相关资源!但如果是堆分配方式的话(如c++使用   new   关键字   或delphi使用create函数),那么如果需要释放实体都必须使用显式声明,(如free   或destroy)
------为了节约内存,优化运行,我们总是动态创建组件。可当用完之后,如果不及时彻底的将其从内存中清理出去,那就有违我们的初衷了。可怎么“杀死”所创建的组件? 比如创建了一个Edit控件,现在想让它消失,但用Edit.Free后,调用Edit.Text却仍然存在……我们知道,光Free是不行的,这只是将Edit所指向的内存空间释放了,但是指针并没有设定为nil,当调用Edit.Text时,Delphi仍然会根据Edit提供的指针访问已经释放的内存区域,所以会产生Access Violation ....错误。所以我们需要在Free后Edit:=nil或者FreeAndNil(只在Delphi5下有效)将指针nil掉,才能保证以后的正常运行。

Delphi和C++的语法区别 (关于构造和析构)的更多相关文章

  1. Delphi与C++的语法区别(六点区别) good

    一.Delphi永远没办法在栈上创建一个对象 下面是一段常见的的Delphi代码,在过程的开头声明本过程所需要的全部局部变量: procedure Foo;var obj: TObject; //这句 ...

  2. delphi 与 C++的基本语法区别

    [1]“=”符号 (1)“=”作为比较符.但是,当定义const常量时,“=”又表示赋值符号.而“:=”作为赋值符号. (2)“=”只表示赋值符号 [2]结构体 (1)record 作为结构体 (2) ...

  3. C++与Java的语法区别

    C++与Java的语法区别 首先,两个大的不同是主函数和怎样编译的不同,接下来是许多小的区别. main 函数C++//自由浮动的函数int main( int argc, char* argv[]) ...

  4. Python2和Python3的一些语法区别

    Python2和Python3的一些语法区别 python 1.print 在版本2的使用方法是: print 'this is version 2 也可以是 print('this is versi ...

  5. python2 与 python3 语法区别

    python2 与 python3 语法区别 概述# 原稿地址:使用 2to3 将代码移植到 Python 3 几乎所有的Python 2程序都需要一些修改才能正常地运行在Python 3的环境下.为 ...

  6. MySQL与Oracle的语法区别详细对比

    MySQL与Oracle的语法区别详细对比 Oracle和mysql的一些简单命令对比在本文中将会涉及到很多的实例,感兴趣的你不妨学习一下,就当巩固自己的知识了   Oracle和mysql的一些简单 ...

  7. Delphi 7以来的Delphi 2009测试版新语法特性

    我晕,Delphi 7 以后增加了这么多有用的语法,我都不知道.真是越学越觉得自己浅薄,自己所作的Delphi项目所用的知识还不够Delphi知识储备体系的十分之一,更别说Delphi还在继续发展. ...

  8. python语法区别

    python语法区别: 大小写敏感 (动态语言:python)变量不用声明 p.s: 静态语言(Java)必须声明变量 语句末尾可以不打分号 可以直接进行数学计算 复制.粘贴功能失效,粘贴到别的地方的 ...

  9. C++语法小记---继承中的构造和析构顺序

    继承中构造和析构的顺序 先父母,后客人,最后自己 静态变量和全局变量在最开始 析构和构造的顺序完全相反 #include <iostream> #include <string> ...

随机推荐

  1. 83. Spring Boot 1.4单元测试【从零开始学Spring Boot】

    在[27. Spring Boot Junit单元测试]中讲过1.3版本的单元测试方式,这里说说1.4和1.3有什么区别之处? 在1.3中单元测试这样子的类似代码: //// SpringJUnit支 ...

  2. Java&Android代码规范

    项目中直接导入Square的代码风格文件.(不导入Google的原因是Square同时提供了Java和Android两套统一风格,Google只提供了一套) Square Code Styles Go ...

  3. 【Luogu】P1462通往奥格瑞玛的道路(二分答案+SPFA)

    题目链接 导致我WA十几遍的原因居然是最大值不够大……以后再也不相信memset(dis,127/3,sizeof(dis))了. 此题先将花费排序,然后二分最大花费,spfa判断解是否可行.spfa ...

  4. Hibernate 笔记 HQL查询 条件查询,聚集函数,子查询,导航查询

    在hibernate中进行多表查询,每个表中各取几个字段,也就是说查询出来的结果集并没有一个实体类与之对应,如何解决这个问题? 解决方案一,按照Object[]数据取出数据,然后自己组bean 解决方 ...

  5. 常州模拟赛d2t3 小X的佛光

    平日里最喜欢做的事就是蒸发学水.[题目描述]小 X 所在的城市 X 城是一个含有 N 个节点的无向图,同时,由于 X 国是一个发展中国家,为了节约城市建设的经费,X 国首相在建造 X 城时只建造 N ...

  6. 程序自动分析(codevs 4600)

    题目描述 Description 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3,…代表程序中出现的变量,给定n个形如xi ...

  7. javascript事件委托和jQuery事件绑定on、off 和one以及on绑定多个事件(重要)

    一. 事件委托什么是事件委托?用现实中的理解就是:有100 个学生同时在某天中午收到快递,但这100 个学生不可能同时站在学校门口等,那么都会委托门卫去收取,然后再逐个交给学生.而在jQuery 中, ...

  8. SQLite数据库相关操作

    一.创建数据库 这里创建了note便签数据表,字段有noteId.noteTitle.noteTime.noteInfo );  // TODO Auto-generated constructor ...

  9. linux磁盘I/O的性能评估

    linux磁盘I/O的性能评估 参考自:自学it网,http://www.zixue.it/. (1)使用iostat命令. [test@localhost /]$ iostat -d Linux - ...

  10. 关于ios异步加载图片的几个开源项目

    一.HjCache  原文:http://www.markj.net/hjcache-iphone-image-cache/ 获取 HJCache: HJCache is up on github h ...