正在热烈讨论,欢迎大家参与,提出自己的见解。
也希望给大家一些启发。敬请关注《Object Pascal:从对象指针谈起》,参与讨论。
http://www.csdn.net/develop/article/10/10124.shtm

解决方案 »

  1.   

    **********************
    Nicrosoft (2001-8-28 23:39:08)  Form := TForm(Obj);
    ShowMessage(TButton(I).Caption);向上映射不好吧...还有,其实VCL对象使用的是引用/值模型,严格来说,并不是指针,因为我们引用对象方法时,是这样:
    Form1.Show();
    而不是
    Form1^.Show();*********************
     Musicwind (2001-8-29 10:50:23)  
    to NicroSoft:
        谢谢你参与讨论。
        对于你说的"向上映射不好吧...",我赞同。因为文章里讨论的其实只是表示一种技术上的可能,
    但并不表示就推荐这么做。谢谢你的意见。
        对于你说的“引用/值模型”,本人第一次听说,真是惭愧。但是我还是坚持认为Form1的的确确是
    一个指针,不能因为访问的时候可以不加^就不是指针,那其实只是Delphi帮助你省略掉了。假如有如下
    的代码:
    var
      Form1: TForm1;
      Form2: ^TForm1;implementation{$R *.dfm}procedure TForm1.MusicBtn1Click(Sender: TObject);
    begin
      Form2 := @Form1;
      ShowMessage(Form2^.Caption);
    end;难道因为"Form2^.Caption"这样的语句就承认Form2是一个指针,而不承认Form1么?
    其实,Form1是指针,Form2同样也是指针,只是Form2是指向指针的指针而已。    不知NicroSoft兄是否有些同意我的看法?
        谢谢讨论。*************************
    chechy (2001-8-29 12:02:47)  
    我赞成Musicwind的观点。向上映射没什么不好。实际上再Delphi中,每个控件都有一个Tag属性,活用这个Tag属性可以节省大量的代码。而这个Tag刚好是整形,4个字节。这就意味着它能够存贮指针。
    不过我更愿意把所谓的对象指针称之为Reference类型。这个概念和Java类似。
    指针这个东西,我一直觉得它的名字起的不好,如果从物理的角度去理解,可能会有更好的感觉。即从Address的角度去理解,而不是将它想象为Pointer。
    另Musicwind,第3节是面向对象的特性,不是指针的特性。**********************
    Nicrosoft (2001-8-29 12:28:24)  
    to Musicwind:var
      Form1: TForm1;
      Form2: ^TForm1;implementation{$R *.dfm}procedure TForm1.MusicBtn1Click(Sender: TObject);
    begin
      Form2 := @Form1;
      ShowMessage(Form2^.Caption);
    end;对于这个代码,我只能说,Form1是引用,Form2是指针。所谓引用,就是对象的别名,也就是可以当作对象来使用的“奇异”的指针,Form1就是这样的,Form2^.Caption说明了它才是指针(BTW,好像老兄比较关注我的文章哦,我写了一篇,你就会有相应的文章出现,哈哈,个人感觉而已,不知道对不对)to chechy:
    我说的向上映射不好,是说这样的映射是“不安全”的。所以编译器需要程序员强制类型转换以确认这样做的后果。面向对象编程的思想中,这样的做法是不被推荐的。*******************************
    Nicrosoft (2001-8-29 12:30:05)  
    另外,Delphi是基于“引用/值模型”的说法,不是我说的,而是Charlie说的。******************************
    chechy (2001-8-29 12:47:03)  
    向上映射是存在不安全性。不过实际应用应该非常广泛的。我记得Nicrosoft你好像写过有关数据与界面分离的文章(大概是这个意思)。实际上我在写一些底层模块时,通常只用TObject,TForm,TComponent这样的基类。而在实际过程中,这些都是具体的对象,那么就需要被转化。此外Delphi的Uses不能循环使用,也迫使某些参数必须使用基类。这些都是向上映射。
    不过在转化是,我倒是建议大家不要使用强制类型转换,而用as操作符。虽然效率差了些,但是对于发现程序错误非常有用。***************************************
    Musicwind (2001-8-29 13:09:51)  
    to chechy:
        很高兴再一次见到你回复我的贴字,谢谢!
        对你所说的活用Tag,表示赞同!因为这其实是我第四节隐含在文字后面想要
    表达的意思。
        不用"指针",而用reference似乎也说得过去。
        至于第三节,有些面向对象的特性,说得好。
      

  2.   

    to hellion(恶人):
       说得好,正有此嫌疑。
      

  3.   

    to Musicwind:虽然引用的本质是指针,但是,对于程序员来说,他们的概念还是需要清晰的区分的引用对于程序员来说,可以看作对象本身,而指针不是。你的第二个例子中:
    PRPerson = ^TRPerson;
    pPerson: PRPerson;
    已经承认了,它是指针
    但是如果这样定义:pPerson: TRPerson; 这样就不是指针,而是声明一个引用了是指针还是引用,不是看调用的地方有没有^,而是看声明的地方。调用的地方可以省略^,只是编译器的特性,却不是语言的特性。 
      

  4.   

    to NicroSoft:
        有些说到正题上了。
        你说 "rPerson: TRPerson; "的声明是引用,并且认为"Form1: TForm1"的声明也是引用,我觉得
    你是自相矛盾的。
        请问,既然都是引用,那么,为什么系统自动分配一个TRPerson记录的内存给rPerson而不需要调用
    new或者Alloc等函数?为什么声明Form1的时候,系统只是分配作为指针所需的内存而已,并没有分配
    创建一个TForm1所需的内存?为什么我们可以直接使用rPerson.Name而对于Form1.Name我们需要事先调用
    TForm1.Create(...)呢?同是引用,有这么大的区别么?
        请注意:"Form1: TForm1;"的声明和"rPerson: TRPerson;"截然不同。
        rPerson和Form1只能有一个是引用,你选择哪个?    请回复,答疑,解惑。
      

  5.   

    我有些糊涂呵
    不过我也同意Form1为一指针
    因为对于VCL类,只能在堆中生成,我们动态建一窗口
    Form1 := TForm1.Create(self)这种行为更像指针
    在c++builder中为
    Form1 := new TForm1(this);
    而对于引用我觉得变量参数是为引用吧
    Show(var i: Integer);
    正如C++中的
    Show(int& i);我是瞎说的欧,呵呵
      

  6.   

    to Musicwind:你不知道“结构”(pascal称为“记录”)和“类”的区别吗?我也有错的,应该这样说,rPerson : TRPerson定义的是一个记录类型的实体,而不是引用,它是值!而Form1 : TForm1声明的是一个引用。这就是所谓的“引用/值”模型。对于简单类型/内建类型,编译器以值模型来使用对象,对于“类”类型的对象,编译器以“引用”模型使用对象。
    声明结构本身就是定义了一个实体,但是类呢?类是“活”的,因此需要创建。
    这还得提到vcl的对象模型。vcl的所有对象是建立在“堆”上的,因此,所有的“类”类型的对象必须通过.Create来创建,Free来释放。而简单类型的对象不需要,他们是创建在“栈”上的,因此一旦声明,就有了实体,并在超出作用域后会被编译器释放其空间。不过,object pascal的引用和c++的引用还是有区别的。c++的引用不允许空引用,不允许动态改变引用所指向的对象,但是,object pascal的引用允许。因为object pascal的对象只能建立在堆上。
      

  7.   

    to NicroSoft:
        对于结构和类的区别吗,我还是知道一点地,我那番话,至少可以反驳你说"rPerson: TRPerson"是引用的那个观点。
        好了,吵归吵,你的许多观点对我还是受益匪浅。经过我一番恐吓,抢白,你终于不吝笔墨
    把有关"引用/值"的模型阐述了一下,谢谢。
        在C++中声明一个类的时候和Delhi的大不相同,同意。
        
      

  8.   

    to xzgyb(回首往事,不堪回首):
        啊呀呀!英雄所见略同呀!
      

  9.   

    引用/值是不是Reference/Value的翻译。如果这样,我也同意类对象是Reference而不是Pointer。
    因为类对象本质上确实是指针,但是从外表看却不像指针调用。(标准的Pascal指针调用必须是P^.Name := 'hello, world';)
    类比其他语言:如Java,Java没有指针,它的类和Delphi类似,也需要new一下,才能创建。Java把它们称之为Reference。再比如C#,虽然它也有指针,和C++一样,需要中规中举的用->操作符。但是它的类使用却和Java相同,也是Reference类型。
    所以我觉得Reference根据贴切。
      

  10.   

    to chechy:
        你是一面旗帜!
      

  11.   

    to chechy:赞同你说的那一段关于"引用/值"模型
      

  12.   

    To Musicwind:
    千万别这么说。你那样说我,我真得找个洞钻进去了。呵呵...
      

  13.   

    再看一遍 xzgyb(回首往事,不堪回首) 的发言,很有些道理呀。
      

  14.   

    Musicwind老大,我存属瞎说的,呵呵,
      

  15.   

    Just Push, want people to discuss !
      

  16.   

    qinghou (2001-8-30 22:49:24)  
    呵呵,很少见到对Object Pascal这么深入的讨论
    个人观点:
    1、在OP中,向上映射没有什么不好,正好相反,向上映射是OP的优点之一。
    Form := TForm(Obj);
    这种语法确实有危险,比较安全的用法应该是
    If Obj is TForm Then Form := TForm(Obj);
    as和is操作符是OP优于C++的地方之一,因为OP的单根结构,使它对RTTI有非常好的支持。想想看,在Delphi的事件处理过程中,往往都是传进来一个TObject类型的Sender对象,如果不对它进行向上映射,那么这个Sender就一点用都没有了。
    2、我赞成Musicwind的观点,Form1: TForm1;这种形式,与其说Form1是一个引用,不如说它是一个指针。OP确实是建立在“对象引用模型”或者说“对象/值模型”(应该是译名不同)之上,但是这种引用和C++的引用完全不同,它其实就是一种指针。
    在OP中,永远不能直接定义一个C++意义上的对象变量,当你定义一个对象变量时,事实上只是定义了一个地址,用以保存对象的内存位置。你必须手动create这个对象。当你访问对象时,事实上也是通过这个地址访问的。这个是大家都知道的。那么你到底将它视为指针还是引用呢?
    Nicrosoft说:
    “虽然引用的本质是指针,但是,对于程序员来说,他们的概念还是需要清晰的区分的
    引用对于程序员来说,可以看作对象本身,而指针不是。”
    这种区别在C++里是有意义的,但Delphi中就不同了。因为在Delphi中,没有哪种引用可以看作“对象本身”,甚至根本就没有“对象本身”。你用来用去的都是对象指针而已,只是没有显式地以指针方式表示出来。我甚至认为OP中根本没有C++中的引用这种概念。
    Nicrosoft认为OP和C++的引用的区别是:
    “c++的引用不允许空引用,不允许动态改变引用所指向的对象”
    那么,请想象一下,有这样一个变量,它存储着一个对象的地址,但这个地址可以为空,也可以动态改变指向的对象。你说它是象一个引用呢,还是象一个指针呢?
    Macro Cantu在《Delphi4从入门到精通》(中文版,P61)里曾经说到这种对象引用模型,描述如下:“它的基本思想是,一个类的每个变量,并不保存对象的值,而是保存一个引用,或一个指针,以来说明对象存储的内存位置。”“使用这种方法的唯一问题是,当声明一个变量时,我们不能在内存中建立一个对象,只是保存对象引用的内存地址——一种指针。”在这里,他是把引用和指针等同起来的。
    Macro Cantu认为对象引用模型是Delphi开发者所做的设计决定中最好的一个。我也觉得这种方式比C++更加清晰。
      

  17.   

    再次引述一下qinghou 提到的Macro Cantu的一番话:它的基本思想是,一个类的每个变量,并不保存对象的值,而是保存一个引用,或一个指针,以来说明对象存储的内存位置。”“使用这种方法的唯一问题是,当声明一个变量时,我们不能在内存中建立一个对象,只是保存对象引用的内存地址——一种指针。”很有见地,深刻!
      

  18.   

    我觉得争论到这里就没有意义了,你说保存对象都是指针,这是废话。但是我不是编译器的实现者,我不需要知道编译器如何实现保存对象的,我所关注的,只是对于程序员来说,引用和指针是有区别的,引用的确可以看作对象本身(对象的别名,见Mashall Cline的C++ FAQ Lite),而指针不是。不需要争论引用是如何实现的,我不管它是用指针实现的或者不是,我不管!也没有必要管!
      

  19.   

    java没有指针,和这个类似的东西叫什么呢?——Reference是不是只有Object Pascal不支持指针的时侯,你才承认它是Reference呢?
      

  20.   

    很明显:var form1 : TForm1;
        form2 : ^Tform1;
    begin
        // some code to create form1
        form2 := @Form1;
        ShowMessage(form2^.Caption);
        ShowMessage(form1.Catpion);
    end;form1和form2从定义就可以看出,他们是有很大区别的。非要说他们是一回事,那么只能说你概念不清,却要找借口——“引用是用指针实现的”至于,Form2.Caption也能编译通过,是纯粹的编译器特性,但是delphi并不等于Object Pascal!看定义,就非常清楚,那么的本质区别,一个用引用方式定义,一个用指针方式定义。
      

  21.   

    小弟,看到各位大虾的讨论,真是精辟,但是Musicwind和NICROSOFT的观点,不同
    from1:tform;
    那么FORM1是指针,还是引用,Musicwind说的很清楚,form1,只是一个,内存地址(
    这里先不说成指针)但这个地址,应该怎么称呼,我想NICROSOFT的话有一定道理
    form2^tfrom;这是指针,大家都知道(没有意见吧)
    Musicwind说,form1看成指针,那么form2就是指向form1的指针了,我不知道
    OP中,多重指针是什么样的,(我水平不高,是来灌水的)
    如果把,form1理解成,指针,是不是,真繁的,我想现在大家,都明白
    怎么回事,就是对于form1的类型,没有达成一致,当然我就更不能下结论了
    希望各位高手给个,结论好吗????
      

  22.   

    发现这样也行
    procedure TForm1.Button6Click(Sender: TObject);
    type
      TTest = record
      ii, jj: Integer;
      end;
    var
      PTest: ^TTest;
      tmp: TTest;
    begin
      tmp.ii := 23;
      tmp.jj := 24;
      PTest := @tmp;
      ShowMessage(IntToStr(PTest.ii));  //不写PTest^.ii也行
    end;
      

  23.   

    其实,不管怎样理解,是不影响使用的。但是,正如byrybye所说,Musicwind如果把form1:TForm1理解为指向指针,那么form2:^TForm1就是指向指针的指针了,很难自圆其说。而我的说法,我想是很清晰的,概念清晰很重要,对于一个严谨的程序员来说当然,我不是说Musicwinde不严谨,但是在这个问题上,我觉得你概念不清。再强调一次,我们都不是编译器的实现者,因此没必要知道引用是如何实现的。
      

  24.   

    to xzgyb: 我希望你看看前面的帖子,你说的这种情况(即使用时可以省略^)是编译器的特性,它允许这样“偷懒”而已。但不是语言的特性。指针就是指针,对象就是对象,引用就是引用。看是否指针就看定义处。
      

  25.   

    再引用一段Mashall Cline对引用的描述吧:请不要将引用看作为指向一个对象的奇异指针,即使引用经常是用汇编语言下的地址来实现的。引用就是对象。不是指向对象的指针,也不是对象的拷贝,就是对象。  
      

  26.   

    delphi 当然不是 Object Pascal!
    我可没说是哦。;)
    但是我们现在讨论的是Borland 版本的Object Pascal,
    请注意:不要将C++中的一些概念强加到Object Pascal里。
    其实已经很清楚了,在Object Pascal中,Form1: TForm1;这样的声明就是定义了一个
    指针,如果你非要说它是引用,当然也可以,那么引用和指针是等同的,至少在 Object Pascal
    (Borland版)中是如此。
    这就是结论。我想qinghou所引的那番话的确很有道理。
    Macro Cantu在《Delphi4从入门到精通》(中文版,P61)里曾经说到这种对象引用模型,描述如下:“它的基本思想是,一个类的每个变量,并不保存对象的值,而是保存一个引用,或一个指针,以来说明对象存储的内存位置。”“使用这种方法的唯一问题是,当声明一个变量时,我们不能在内存中建立一个对象,只是保存对象引用的内存地址——一种指针。”在这里,他是把引用和指针等同起来的。
    Macro Cantu认为对象引用模型是Delphi开发者所做的设计决定中最好的一个。这样做更加清晰,我也这么觉得。
      

  27.   

    首先,你并没有定下“只讨论Borland版本的OP”的前提!其次,引用概念并非只有OP中有,没有谁强加谁的问题!再次,引用<>(或者 !=) 指针最后,我不管borland如何实现引用,你不能做任何假设或断言,因为以后引用也可能不用指针来实现,我想你知道什么是“面向接口编程”吧
      

  28.   

    Macro是作为编译器的实现者来阐述这个问题的
      

  29.   

    欧,我原先以为只有TObject的派生类可以省略^ 像 Form1.Show而不用写成Form1^.Show
    而指向记录的指针也可以这么写
      

  30.   

    我也同意引用就是对象
    而我感觉用不用^,只是对pascal概念的一种体现,并不影响使用.
      

  31.   

    form1就是个指针
    form1和form1^并没有区别,只是方便大家书写程序
    否则要是每个对象都要^,岂不是很累
    你甚至可以定义个Integer来保存form1
    a = integer(form1);等你那次需要的时候,就可以这么写
    form2 := TForm(a);
    然后用Form2
      

  32.   

    to NicroSoft:
        对,生活就是折腾,没错。to byrybye:
        结论由个人自己下吧,看来要想取得一致的看法很难了。