2 u010250295 u010250295 于 2015.05.26 17:28 提问

delphi中对象create之后,默认存放的路劲是?

例如:Tinifile,Tbitmap,等等,不带路劲名,直接create('文件名.ini'),
怎么判断是否创建成功,是不是只有提前判断同名文件是否存在一种方法?

6个回答

qq_27361099
qq_27361099   2015.05.26 22:56
已采纳

在D中每个应用程序可以获得的内存空间分为两种:堆(heap)和栈(stack)。
堆又称为“自由存储区”,其中的内存空间的分配与释放是必须由程序员来控制的。例如,用GetMem函数获取了一定大小的内存空间,则在使用完后,必须调用FreeMem函数将空间释放,否则就会发生所谓的“内存泄漏”。“借债还钱,天经地义”。
栈又称为“自动存储区”,其中的内存空间的分配与释放是由编译器和系统自动完成的,不需要程序员过问。函数调用时按值传递的参数所占空间、函数中的局部变量等,都是在栈中被分配空间的。
Objecgt Pascal遵循所谓的“引用/值”模型。无论在参数传递还是变量定义中,简单类型(如Integer、Cardinal、char以及record等) 被按值传递或使用,其内存空间从栈中分配。而复杂类型(class)则被按引用传递或使用,其内存空间从堆中分配。在Object Pascal中,所有对象(类类型的)都被建立在内存的堆空间上,而非栈上。因此在创建对象时,其构造函数不会被编译器自动调用,也没有C++中所谓的 “默认构造函数”(默认构造函数:在C++中声明一个变量或一个类实例时候,自动调用相应的购造函数为该变量或实例分配内存控件,在D中的类类型对象都需 要程序员调用构造函数对其进行显式构造,分配内存)调用构造函数来创建对象以及调用析构函数来消灭对象都是程序员的职责。
定义构造函数使用Constructor关键字。按惯例,构造函数名称为Create(当然也可以用其他名称,但那绝非优良的设计)。如
Public
Constructor Create(strFatherName, strMotherName : String);
要创建出一个对象,首先需要分配对象本身所占用的内存空间,然后执行类的构造函数,以初始化各数据成员、申请对象需要的资源或创建其内部包含的子对象。构 造函数代码调用的是system.pas文件的第8949行的_ClassCreate函数(以Delphi 6为准),该函数具体为每个对象分配合适的内存。这个动作也就是所谓的“编译器魔法”(Compiler Magic),由这个动作完成真正的对象的内存分配,一个对象在这个时候已经有了外壳。
内存分配完成后是调用类的构造函数,即TMyClass.Create(),以初始化数据成员。构造函数由定义类的程序员编写,也就是说,将对象初始化成何种模样是由程序员决定的。至此,一个对象已经诞生了。
由于对象本身所占内存的分配是由编译器完成的,因此即使没有构造函数,对象也一样可以被构造。构造函数的职责只是初始化对象的数据成员,没有构造函数只意 味着不会对数据成员进行初始化而已,编译器会对所有数据进行清零初始化。此外,由于Object Pascal中所有类(除了TObject类本身)都是从TObject类派生,因此编译器会调用TObject.Create()构造函数。不过,这个 函数只是一个空函数(只负责为类分配内存空间,但不进行类中成员的初始化工作)。
注意:在方法或函数中声明一个类类型变量的时候。编译器给这个变 量一个4字节的地址空间在栈上。它并不代表任何东西,只是一个指针而已(所以类类型变量名称实质上都是指针而已,普通的赋值操作,赋予的也只是指针地址而 已,并没有给新变量另辟空间存储)。在函数或方法中,定义的类类型变量需要被初始化后才能使用,也就是被create后才能被正确访问。create后在 堆中分配相应的空间,而声明的变量则指向该段内存。但是当函数结束后如果该类类型变量不需要被传递到外界使用,那么应该及时的free掉,也就是进行析 构,否则将发生内存泄漏,即该内存空间一直都被该变量占用。如果要传递到外界,那么也就是result:=类类型变量A(result是编译器给函数的默 认的一个变量,未赋值前也是一个4字节地址控件而已,负责传递变量)。result:=类类型变量A后,result指向了类类型变量A,也就是说 result和A都指向同一个对象,修改result和A都是一样的结果。这种情况下,也就是类类型变量A需要被传递时候,在函数内不需要被free.但 是函数将A传递给主调函数中的类类型变量B后,也就是B:=A,B也指向A的内存空间,那么在B的使用期结束后就需要对B进行free,也就对A进行 free了,就不容易出现内存泄漏。
定义析构函数使用Destructor关键字。按惯例,析构函数名称为Destroy。与构造函数类似,如果在类中没有特殊的资源需要被释放,也可以不定 义析构函数,TObject同样定义了一个空的析构函数。在析构对象的时候,应该调用对象的Free()方法而不是直接调用Destroy()。这是因 为,在TObject的Free()方法中会判断对象本身是否为nil,如果不为nil则调用对象的Destroy(),以增加安全性。永远不要直接调用 对象的Destroy(),而应该是Free()。要销毁一个对象,其顺序与创建对象正好相反。首先是释放对象申请的资源以及销毁内部的子对象,之后是回 收对象本身所占的内存空间。
销毁一个全局对象变量的时候,通常将对象设置为nil,这样就不会留下一个含非法指针的变量。当析构函数或者一个由析构函数调用的方法引用了该变量的 时候,如果该变量成了nil,则可以避免任何潜在的问题。free方法也不会自动将对象置为nil,所以在调用free之后,最好是在手动将对象设置为 nil。可以使用sysutils单元中的方法freeandnil过程——freeandnil(obj)。

    构造函数和析构函数的目的在于一个类可以像普通类型那样初始化和销毁,从而保证了封装。在一个类的构造函数中分配的资源尽量要记得在析构函数中销毁。

    另外,在VCL类中,对象的销毁还应注意顺序,VCL的组织形式:属主(owner)机制。从TComponent开始,VCL类的构造函数就带有一个参 数AOwoner,它决定了这些类之间的树型关系。比如一个button放在form上,那么button的aowoner就是form。那么析构 form的时候,会先通知button析构。即析构的时候会通知自身拥有的对象先行析构,如此递归下去。这种属主机制是设计模式中典型的结构性模式 COMPOSITE(组合)。而递归析构的方式是典型的行为模式中的Observer(观察者模式),这是VCL中的消息处理的基本模式。

总 结:简单类型存放在栈中,由编译器管理其内存空间。声明时候就已经分配了内存空间。赋值后的两个变量属于不同的变量。但是类类型存放在堆中,需要程序员管 理,需要对其进行create和destroy,赋值以后被赋值的对象仍然指向赋值的变量内存空间,并没有创建属于自己的内存空间。

caozhy
caozhy   Ds   Rxr 2015.05.26 17:33

默认放在程序的工作路径。所谓工作路径,如果你是在ide中启动,那么很可能和delphi主程序在一个路径。
如果是双击程序启动,那么和程序exe在一个路径。你也可以给程序创建一个快捷方式,并且在快捷方式的属性中设置工作路径。

u010250295
u010250295   2015.05.26 17:49

好像不对,例如:
procedure TForm1.Button1Click(Sender: TObject);
var INISVN:Tinifile;
begin
INISVN:=Tinifile.Create('BenDaS.ini'); // BenDaS.ini'
edit1.Text:=INISVN.ReadString('SYSDB','服务器名','SONG');
INISVN.WriteString('SYSDB','服务器名','SONG');
end;
创建的文件最后在C:\Windows\
这个路径是怎么配置的,可以指定生成到项目编译realse的路径下么?
其他类似的路径又是怎么设定的。
此外,对象Create之后,我们怎么知道对象是否被成功创建,
还是只能先判断是否存在,不存在创建,存在先删除或不创建?

teclick
teclick   2015.05.26 17:57

我一般用create(changefileext(applicationname, ini))

devmiao
devmiao   Ds   Rxr 2015.05.26 17:57
seth0805
seth0805   2015.05.29 07:09

TBitmap.SaveToFile('1/bmp')

Csdn user default icon
上传中...
上传图片
插入图片