Delphi中对象的创建,理解对象名与对象实体的本质区别

  2015.08.06我总结的关于New和指针的问题(见此博客),最近在使用Delphi的面向对象的时候,发现很多类似的问题,现在也要总结一下。

  目前以下的总结是针对Delphi的,对于C++我还没有实验过。

情况一:对一个对象变量多次Create         

首先说一下对象声明的时候

var
    ObjectA: ClassA;

  比如有一个类ClassA,用它来声明一个变量 ObjectA: ClassA;

  注意这个时候的ObjectA相当于一个空指针,因为此时并没有创建一个对象实体(参看博客:http://www.cnblogs.com/xumenger/p/4437231.html

接着说一下创建一个对象的时候

ObjectA:= ClassA.Create;

   如上面的代码,此时才真正在内存中创建了一个对象实体,ObjectA指向这个实体。

其实还可以通过ObjectA再创建一个实体

ObjectA:= ClassA.Create;

  此时又新建了一个对象实体,此时ObjectA指向这个新的对象实体,但是因为ObjectA指向了新的对象实体,而又没有对象指针指向原来的对象实体,所以就造成了原来的实体的丢失,也就是内存泄露

  以一个小例子更好的说明

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  ClassA = class
  public
    name: string;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
var
  ObjectA: ClassA;
begin
  ObjectA:= ClassA.Create;
  ObjectA.name:= ‘xumeng‘;

  ObjectA:= ClassA.Create;
  if ObjectA.name =‘xumeng‘ then
    ShowMessage(‘没有新建对象‘)
  else
    ShowMessage(‘新建了对象,并且ObjectA指向了新的对象,而原来的对象实体丢失了‘);
end;

end.

点击按钮,程序运行的效果图如下:

代码讲解

  这个例子中,再按钮的点击方法中先ObjectA:= ClassA.Create;,此时新建了一个ClassA对象实体,ObjectA指内存中的该实体。

  然后将ObjectA的name 变量设置为 ‘xumeng‘。

  紧接着又进行了 ObjectA:= ClassA.Create; 此时又新建了一个ClassA对象实体,ObjectA指向新的对象实体。因为通过上面的代码运行之后可以看到这时候对象的name 不是 ‘xumeng‘ 了,所以就不再是原来的对象了,所以也就说明如果这样可能造成内存泄露。大多数的对象如果出现这种情况,因为丢失了对象的指针也就没有办法通过指针对对象进行释放,所以也就造成了内存泄露;也存在这样的情况,比如一个线程对象,其Execute方法是执行一个循环然后结束,并且将其FreeOnTerminate属性设置为True,那么该线程就会在执行完Execute之后自行释放,这种情况下就不会造成内存泄露。但是正如文字所描述的,这种情况实在是要有太多的前提条件,所以为了不出现内存泄露,保证软件项目的质量,一定要尽可能避免上面所提到的情况。

情况二:多个对象变量指向一个对象实体        

  这个就可以直接来个代码来看一下

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  ClassA = class
  public
    name: string;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
var
  ObjectA, ObjectB: ClassA;
begin
  ObjectA:= ClassA.Create;
  ObjectB:= ObjectA;

  ObjectA.name:= ‘xumeng‘;
  ObjectB.name:= ‘xumeng changes his name‘;

  ShowMessage(ObjectA.name);

end;

end.

点击按钮,程序运行的效果如下

代码讲解

  首先是ObjectA:= ClassA.Create; 就是在内存中创建了一个ClassA对象实体,然后ObjectA指向该对象实体。

  然后将ObjectA 赋值给ObjectB,注意这里的效果是ObjectB也指向了ObjectA所指向的那个内存实体,并没有新建一个内存实体。

  所以先通过ObjectA.name:= ‘xumeng‘; 给这个内存实体的name 变量赋值之后,再通过ObjectB.name:= ‘xumeng changes his name‘; 就修改了这个对象实体的name。

  像上面的代码就只是将两个指针指向了同一个内存实体而已。注意只有通过类的Create方法才能真正在内存中创建实体。变量名就只是相当于一个指针,用于指向内存中的实体。

  上面的代码的效果对于Delphi里面的所有类都是一样的原理!!

另外一种情况讲解                  

一些特殊的线程

  往往很多的时候你会看到这样的线程代码

type
    MyThread = class(TThread)
    ......
    end;

begin
    MyThread.Create;
    MyThread.Create;
end;

  这里面是创建两个线程,并且线程运行,很多时候其实以这样方式创建的线程是在Execute方法里将其FreeOnTerminate设置为True,而且其Execute 函数是一个有限的循环,这样线程就一定会在未来某个时间点结束运行并且自己释放相关资源。

  所以这样就不需要通过对象的变量名再去显式的操作线程。

其他的大多数情况

  其他的大多数的类,需要通过指向对象实体的变量名(指针)来显式的释放资源

  还有线程类(比如没有将FreeOnTerminate设置为True的线程,比如无限循环执行的线程),需要通过指向对象实体的变量名(指针)来显式结束线程并且释放资源。

  例程

type
    ClassA = class
    public
        name: string;
    end;

begin
    ClassA.Create;
    ClassA.Create;
end;

  像上面的代码,创建了对象之后也就立即丢失了对象,这样就只能造成内存泄露,所以坚决杜绝!!

  一定要保证创建的对象在使用完之后都释放掉,不要造成内存泄露。

时间: 2024-10-14 00:17:50

Delphi中对象的创建,理解对象名与对象实体的本质区别的相关文章

Delphi中DLL的创建和使用【转】

Delphi中DLL的创建和使用     1.DLL简介:   2.调用DLL:   3.创建DLL:   4.两个技巧:   5.初始化:   6.例外处理.            1.DLL简介     DLL是Dynamic-Link   Libraries(动态链接库)的缩写,库里面是一些可执行的模块以及资源(如位图.图标等).可以认为DLL和EXE基本上是一回事,只是DLL不能直接执行,而必须由应用程序或者其他DLL调用.DLL为应用程序间的资源共享提供了方便,同时也是多语言混合编程的

DDD实战12 值对象不创建表,而是直接作为实体中的字段

这里的值对象如下风格: namespace Order.Domain.PocoModels { //订单地址 //虽然是值对象 但是不继承ValueObject //因为继承ValueObject会有Id属性 我们不为它创建独立建表不要Id public partial class OrderAdress { public string Province { get; set; } public string City { get; set; } public string Zero { get

ActiveX数据对象之事务控制在VB和DELPHI中的应用

本文发表在中国人民解放军"信息工程大学"学报 2001年第3期. ActiveX数据对象之事务控制在VB和DELPHI中的应用                     马根峰1   ,  孙艳2  , 宋伟1                       ( 1.重庆邮电学院 ,重庆,400065 :2. 铁道部第十九工程局四处,通辽,028000  ) 摘要      事务控制是数据库应用系统中的关键技术之一,本文一开始先对事务控制的概念以及微软的 ActiveX数据对象(ADO)的事

对象的创建

创建一个类,实际上是定义了一种新的复合数据类型.声明该类的一个变量,就是声明该类的对象过程.创建对象包括对象的声明和实例化两步. 1.对象的声明 对象的声明主要是声明该对象是哪个类的对象,语法如下: 类名 变量名列表: 注:变量名列表可包含一个对象名或多个对象名,如果含有多个对象名,对象名之间采用逗号分隔开.当声明一个对象时,就为该对象名在栈内存中分配内存空间,此时它的值为null ,表示不指向任何对象. 2.对象的创建 在声明对象时,并没有为该对象在堆内存中分配空间,只有通过new 操作才能完

对象的创建和存在的时间

从技术角度说,OOP(面向对象程序设计)只是涉及抽象的数据类型.继承以及多形性,但另一些问题也可能显得非常重要.本节将就这些问题进行探讨.最重要的问题之一是对象的创建及破坏方式.对象需要的数据位于哪儿,如何控制对象的“存在时间”呢?针对这个问题,解决的方案是各异其趣的.C++认为程序的执行效率是最重要的一个问题,所以它允许程序员作出选择.为获得最快的运行速度,存储以及存在时间可在编写程序时决定,只需将对象放置在堆栈(有时也叫作自动或定域变量)或者静态存储区域即可.这样便为存储空间的分配和释放提供

对象的创建和存在时间(持续更新)

 摘自:Think In Java 从技术角度说.OOP(面向对象程序设计)仅仅是涉及抽象的数据类型.继承以及多形性.但还有一些问题也可能显得很重要.本节将就这些问题进行探讨.最重要的问题之中的一个是对象的创建及破坏方式.对象须要的数据位于哪儿,怎样控制对象的"存在时间"呢?针对这个问题.解决的方案是各异其趣的. C++觉得程序的执行效率是最重要的一个问题,所以它同意程序猿作出选择.为获得最快的执行速度.存储以及存在时间可在编敲代码时决定.仅仅需将对象放置在堆栈(有时也叫作自己主动或定

浅谈对象的创建、内存布局和访问定位

在此简单的记录一下<深入理解Java虚拟机>第2章的2.3节内容. 对象的创建 这里的对象的创建是指普通的对象(不包括数组和Class对象).对象的创建简单来说就是执行new的时候,虚拟机做出对应的响应.让我们看看一下虚拟机创建对象的过程: 1.虚拟机遇到new指令时,首先尝试在常量池中定位到对应类的符号引用,并检查这个符号引用代表类是否已被加载.解析和初始化过.如果没有,那必须先执行相应的类加载过程(后续会写一下关于类加载的问题). 2.类加载检查通过后,为新生对象分配内存.对象内存的大小在

对象的创建和存在时间

从技术角度说,OOP(面向对象程序设计)只是涉及抽象的数据类型.继承以及多形性,但另一些问题也可能 显得非常重要.本节将就这些问题进行探讨. 最重要的问题之一是对象的创建及破坏方式.对象需要的数据位于哪儿,如何控制对象的"存在时间"呢? 针对这个问题,解决的方案是各异其趣的.C++认为程序的执行效率是最重要的一个问题,所以它允许程序员 作出选择.为获得最快的运行速度,存储以及存在时间可在编写程序时决定,只需将对象放置在堆栈(有时 也叫作自动或定域变量)或者静态存储区域即可.这样便为存储

《JVM》(四)Class类文件结构,对象的创建

Class类文件结构 class文件是一组以8字节为单位的二进制流,只有两种数据类型:无符号数(基本数据类型),表(复合数据类型) 魔数 版本号 常量池(占class空间最大的数据之一,从1开始计数) 1.字面量 :接近于java层面的常量概念,如字符串,声明为final的常量 2.符号引用:类和接口的全限定名,字段和方法的描述符 字段描述符:描述字段数据类型 方法描述符:描述方法参数列表和返回值 访问标志 类索引,父类索引,接口索引集合 字段表集合(描述接口或类中声名的变量,不包括方法中的局部