关于对象实例化的一个小问题。想了想,没有想明白。(50分)

  • 主题发起人 白衣书生
  • 开始时间
M

majorsoft

Unregistered / Unconfirmed
GUEST, unregistred user!
to foresail,
看来你是个典型的C++主义者。C++学的不错哦。
我确实犯了些错误,因为不存在栈对象,所有的对象都在heap堆中创建的,请原谅!
在C++中:
TmyClass a;
这样确实创建了对象,因为它使用的是栈内存,它调用默认构造函数。
但我要提醒你的是这是在delphi中。它们的实现机制还是有点不同,其实用堆来存储对象有其优点,他让用户自己显示地创建和销毁,什么时候创建什么销毁了,一清二楚,可读性非
常好,而且我用函数创建对象,并不需要拷贝,等等优点。如果用栈的话,真有点不好,这都要感谢Object Pascal的发明者们
对于你说的第三点,请看清楚我的程序:
Tmyclass=class
public
procedure showMsg;
end;
procedure Tmyclass.showMsg;
begin
showmessage('ok');
end;
我是说的是"因为ShowMsg是静态方法"。
最后再重申明一下,在delphi中所有的对象名都是引用/指针!这又与C++中不同!
在对某样事物不了解的情况下,我们应该学会闭嘴。
对于你的“
怪不得現在有這麼多人哀嘆Delphi程序員工資低.Delphi程序員的水平不高工資怎麼能高?”
你说的是事实,我现在水平也很菜,delphi的VCL帮我们做我很多事情,使得入门也很容易,使用很方便(不知道你为什么会用delphi,也是看中她这一点吧),但这往往促使我们delphi程序员的懒惰性。VCL比那个MFC不知好到那儿去了,我打算学习VCL,尤其是它的设计思想,以摆脱菜鸟帽子,有同想法者,欢迎加我QQ122646527,认证delphi or VCL

 
S

ShadoWind

Unregistered / Unconfirmed
GUEST, unregistred user!
我来补充一点……
楼主的这种调用方式有个先决条件就是在调用前没有别的对象被创建。
如果这样:
var
a:myclass;
b:TLabel;
begin
b:=TLabel.create(self);
a.abc;
end;
程序就会出异常……
还有在创建前后a.abc指向的地址是不一样的……
还有……如果在ButtonClick事件中Show出a的ClassName……有时候会看到的不是TButton而是TForm1……
 
Z

zjan521

Unregistered / Unconfirmed
GUEST, unregistred user!
通过类而不是类实例能够安全饮用的方法只有Class Function
而其他普通的类函数都有一个默认的Self的参数指向类实例,而类自身这个Self是没有意义的
btw
Delphi里边不会自动调用Constructor的,
 

风雨燕归来

Unregistered / Unconfirmed
GUEST, unregistred user!
to majorsoft and foresail:
两位好:
首先我是菜鸟一只,不要以我为敌。
其次才是想问几个问题:
1、基本数据类型与类是如何区分的,有人认为基本数据类型也可能当成是类,在Delphi中基本数据类型不需要CREATE,而类却需要,不知道C++需要吗?而楼主好像也就是存在这个疑问,你俩吵了半天,大家还是不明白,当然,高手嘛。(我是说我很菜,可不是说在这的人都菜)
2、类或者对像在内存之中的存在形式是如何的,函数呢?我知道堆中数据可以自动分派,回收,而栈中却不行,delphi的变量、函数、还是对像,究竟是什么?一个变量和一个函数又是如何的标明是某个类的成员呢?变量和命令又是存储在同一块内存中吗?再就是一个类被实例化的时候,其基类是否也同时实例化了吗,若无,那它怎么能调用其超类的成员函数呢,若有,它被初始化成了什么?怎么引用它呢?是parent吗?若还想调用它的祖先类,又该如何?
3、再就是

showmessage是誰的靜態方法? 再說showmessage跟我們討論的根本無關,因為我們程序里調用的是a.ABC,這裡ABC定義成TMyClass的靜態方法了嗎?

这句有理,但a.ABC不是静态方法,showmessage究竟是谁的成员函数?a.ABC又为什么在实例化之前可调用了呢?什么?已经实例化了,那为什么其它类又不能了呢?
 
Z

zjan521

Unregistered / Unconfirmed
GUEST, unregistred user!
ShowMessage是独立的函数 至少在表象应用上看,他没有和雷车上关系,并且a.ABC没有调用使用Self这个指针。所以可以把他看成静态函数
静态函数之所以成为静态,意义也就是在与他不访问类实例才会有的Self(包括各个数据域,访问这些数据域的方法)
至于类和对象的关系,包括内存管理等等,建议还是攻一下书本,特别的Delphi和C++的很多地方是不一样的,因为不是一时半会能说清的。
比如你要知道,对象可以看作一段内存区域+一段代码区域 在内存区域中有指针指向代码区域。而代码也就是函数,自然而然就是存在的,不过是动态还是静态还是什么样的方法。所以自然就能够调用。但是这段内存区域是不存在的,所以如果你的方法里边访问了Self相关的东西,那么调用就会失败
你可以看一下 自带的代码
TObject.Create
Object.Create
也就是Create可以被类调用产生新的对象,也可以被对象调用(当然通常不会这样,)
里边关于Self的判断 相信会有帮助
 
T

TryCreate

Unregistered / Unconfirmed
GUEST, unregistred user!
我的观点:
1.可以这样调用 a.ABC
是因为ABC是静态方法,静态方法的地址是在编译期就确定的,并且你没有对象中的数据;
2.当在类中加了vstr:String这个字段时,也没出错,因为字符串本来就是指针,其值是根据Self指针得到的,本例中的Self指针并不正确,但是合法的
3.类中方法的调用都会传入一个Self指针,Delphi中传入该指针是用ebx寄存器的,在调用abc时,ebx中保存的是Click方法的Sender值,所以会出现ClassName为TButton或者是TLabel.
以上是我的看法。
 
Y

yangh888

Unregistered / Unconfirmed
GUEST, unregistred user!


~!
 
M

majorsoft

Unregistered / Unconfirmed
GUEST, unregistred user!
哎大家都看错了,
我说的是自定义的showMsg(Tmyclass的方法)是静态函数,并没有说showmessage.
procedure Tmyclass.showMsg;
begin
showmessage('ok');
end;
我强调过了一次,竟然还是这样,看来还是要用楼主的名字好些
 
H

hsb0307

Unregistered / Unconfirmed
GUEST, unregistred user!
这个问题对我们操鸟很有帮助
 
L

leasun

Unregistered / Unconfirmed
GUEST, unregistred user!
这可能是Delphi的一个bug。一个非类方法无论如何不应该通过类来调用,否则会影响到对象的维护性
 

风雨燕归来

Unregistered / Unconfirmed
GUEST, unregistred user!
楼上这位朋友还有点创意。
 
B

bluebridge

Unregistered / Unconfirmed
GUEST, unregistred user!
foresail说的是错的。
Delphi和c++不一样,Delphi的对象全是创建在堆上的,不显式调用Create函数对象就不会创建。
c++对象既可以建在堆上,也可以建在栈上。如果在局部变量里声明一个对象,会自动调用缺省的Constructor,推出函数时自动调用DeConstroctor。
 
D

delphifaq

Unregistered / Unconfirmed
GUEST, unregistred user!
这应该是 数据区 与 代码区 的问题
在内存中类的方法只有一份,不管其有多少成员变量,而成员变量是每个实例一份
即 类的方法 是静态的
所以 上例在不访问成员变量时,方法调用是正确的
 
B

bluebridge

Unregistered / Unconfirmed
GUEST, unregistred user!
showMsg并不是静态函数,只是一个普通的成员方法。
类的成员方法调用时,比如调用a.showMsg,实际调用的是TMyClass.showMsg,但会传给方法一个Self值(即a的地址),在这里Self并没有被用到,所以不管Self是什么,showMsg都会成功调用。如果showMsg方法内部访问了类内部的成员变量,则调用肯定失败,因为这个成员变量要靠Self去寻找,在这里Self是nil或者错误的值。
至于a到底是nil还是别的什么值,跟编译选项有关。在打开优化的情况下,编译器为了节省代码量,不初始化a,a是一个错误的值。如果不使用优化,则编译器会先将a初始化为nil。
 

风雨燕归来

Unregistered / Unconfirmed
GUEST, unregistred user!
就算是你不定义,你也可以使用任何一个类的属性。
 

风雨燕归来

Unregistered / Unconfirmed
GUEST, unregistred user!
一、showMsg是一个静态函数,为什么?不信你重载它一下,看系统提示什么?
二、让大家明白一下,什么是静态函数?
静态成员或是静态函数与类基本无关,你完全可以把它当成是一个全局函数,只是它从属于类而已,它在任何类的初始化之前被创建,不信?我也没办法。在BUTTON的单击中调用a.classname显示的是TBUTTON,其实就能说明此点(因为self此时指向的是Button)。
三、对于:foresail所说:

var a:TMyClass 不存在什麼指針的問題,這就是一個對象實體.

我认为a不过是一个标志符而已,当然是一个指针或是应用,但是一个常指针或是常引用。
foremail也不过是几个字母而已,难道能代表了你自己的实体吗?

四、上面大家所说的类空间等等,类的方法等等。我认为全部不正确。
类不过是函数与变量的组织方式而已,是一种理论上存在的东西,在实际的程序执行中并不存在?(只有实例存在)你之所以能够调用该类的方法(无论是静态还是动态,亦或是虚函数),是由于该类(包括其所有的祖先类)已经都已实例化(当然是从TObject开始的),只不过由系统完成,不为你所知而已。而所有的类又通过一个运行时间类的东东把它们关联起来。别说我照搬C++,首先这不是C++,而是OO,只要是OO,那么就是如此。

五、delphi的所有基本类型建在堆中,其余建在栈中。
 
A

Another_eYes

Unregistered / Unconfirmed
GUEST, unregistred user!
>>>就算是你不定义,你也可以使用任何一个类的属性。
-->如果不考虑这样使用后99%的出错可能的话,同意该观点。

>>>你之所以能够调用该类的方法(无论是静态还是动态,亦或是虚函数),是由于该类(包括其所有的祖先类)已经都已实例化(当然是从TObject开始的),
-->这个观点是错误的。 在delphi中系统隐含做的初始化工作只是事先建立了各个类的VMT(virtual method table 即虚方法表),而并没有实例化任何一个类。 类实例实际上是包含一个指向相应类VMT的指针和本类及所有父类中的所有内部变量的record结构(TObject.InstanceSize返回的就是这个record的大小),详细说明请参阅delphi帮助中delphi language guide里Memory management一节。

>>>delphi的所有基本类型建在堆中,其余建在栈中。
-->很不幸,又是一个错误的理解。 delphi中的类与类实例都在堆中,而基本类型(比如integer, record, static array ...)在最终可执行代码中根本没有相应的类型定义存在,它们的变量则根据定义处的不同可能在堆中也可能在栈中。delphi的类变量实际就是个指针,它指向你显式调用create方法创建的类实例(这个类实例肯定在堆中,而这个类变量也就是指针本身则有可能在栈中), 当然如果你没有调用create,那么这个变量的初始值是nil.
 
M

majorsoft

Unregistered / Unconfirmed
GUEST, unregistred user!
这个问题其实很好理解!!

在delphi中,成员函数在对象中并没有存储,就连方法指针都没存储!!
不信你可以做个实验:
TsizeAlignTest=class
private
i:integer;
ch1,ch2:char;
j:integer;
public
procedure showMsg;
procedure virtMtd
virtual;
end;

memo1.Lines.Add('**********Object Created in heap**********');
memo1.Lines.Add(inttostr(sizeTest.InstanceSize)+':InstanceSize');
memo1.Lines.Add(inttostr(integer(sizeTest))+'<-start Addr');
memo1.Lines.Add(inttostr(integer(@(sizeTest.i)))+'<-sizeTest.i');
memo1.Lines.Add(inttostr(integer(@(sizeTest.ch1)))+'<-sizeTest.ch1');
memo1.Lines.Add(inttostr(integer(@(sizeTest.ch2)))+'<-sizeTest.ch2');
memo1.Lines.Add(inttostr(integer(@(sizeTest.j)))+'<-sizeTest.j');
//结果显示
16:InstanceSize
14630724<-start Addr
14630728<-sizeTest.i
14630732<-sizeTest.ch1
14630733<-sizeTest.ch2
14630736<-sizeTest.j
数据成员就占了16个字节!,两个成员函数
procedure showMsg;
procedure virtMtd
virtual;在对象的存储区中根本没占一点空间!!
这样一来,在Delphi中,我们调对象的方法(成员函数)的时候根本不需要对象时候存在,只要该对象方法没有使用数据成员和虚函数(为什么虚函数不能?因为虚函数的调用需要知道对象实际类型,此时对象一定要存在!)
到这里这个帖应该可以结了吧
 
A

aimingoo

Unregistered / Unconfirmed
GUEST, unregistred user!
哈哈。这个问题被书给选了。这是一个普遍的概念问题。wr960204的第一个答案就对了。
 

风雨燕归来

Unregistered / Unconfirmed
GUEST, unregistred user!
to Another_eYes:
听君一席话,胜读十年书,改天请教,其实那些都是俺照着VC蒙的,认为delphi也是这样.
 

Similar threads

S
回复
0
查看
948
SUNSTONE的Delphi笔记
S
S
回复
0
查看
769
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
662
import
I
顶部