大家都知道一个类的Create可以理解为类方法,就如MyObject := TMyClass.Create;但是在Delphi里类方法是无法对对象的数据成员进行访问的,但是大凡Create里都要对对象的数据成员进行一些初始化,那这不就矛盾了吗?请高手指教!
  另外,在Delphi里方法指针是否可以就理解为C++里的类的成员函数指针?请高手们不吝赐教!

解决方案 »

  1.   

    Q:
    Delphi里类方法是无法对对象的数据成员进行访问的
    A:
    你的这个描述本身就有问题。一个对象的公用数据成员就可以其它对象被访问!
    Q:
    大凡Create里都要对对象的数据成员进行一些初始化
    A:
    你申明一个类,在这个类中定义的一些数据成员(不论是共有、私有、保护),难道这个类的本身还不能访问吗?----完全可以(所以用Create可以对类的数据的成员数据进行初始化)!!
    只是这个类的成员变量,不一定能被别的对象访问!
    Q:
    在Delphi里方法指针是否可以就理解为C++里的类的成员函数指针?
    A:
    可以!
      

  2.   

    谢谢!不过我还是有一点不明白,类方法是进行的类级别的操作,而在<<DelPhi高手突破>>说Create是可以理解为类方法的,但是类方法是不能对数据成员初始化的!
      

  3.   

    <<DelPhi高手突破>>说Create是可以理解为类方法的,但是类方法是不能对数据成员初始化的
    那就一定对吗?????
      

  4.   

    我不是想抵毁<<Delphi高手突破>>的作者Nicrosoft(我还没有这个功力),应该说每个人都会犯错误的。有兴趣可以看看这篇帖子:
    http://www.csdn.net/develop/read_article.asp?id=12430
      

  5.   

    Delphi里类方法是无法对这个类的数据成员进行访问的
    是对的,无论数据成员私有也好,还是公有也好,在一个类的方法里无法
    访问这个类里的数据成员抄一下<<delphi技术手册>>中的一段话Classes and Objects类和对象可以将类想象为一种特殊的记录。与记录相似的是,一个类描述的是一种特殊的类型,它由任意多个部分组成,每一个部分称为一个字段。与结构不同的是,一个类可以包含函数和过程(称为方法method),以及属性property。一个类可以继承自另一个类,因此,它继承了祖先类中所有的字段,方法,以及属性。一个对象(Object)是一个类的动态实例。对象总是从堆中动态分配得来,因此一个对象引用(object refrence)更象一个指针(但是不需要pascal的^操作符)。当你将一个对象引用赋值给一个变量时,Delphi只是复制了指针,而不是复制整个对象实例。程序中不再结束使用一个对象时,应当调用Free方法显式地释放该对象。Delphi没有提供自动的垃圾收集机制(后面一章中的提到的接口除外)。为简短起见,术语“对象引用”简称为“对象”,但是对象更精确的表述应当是一块内存,Delphi在其中存放该对象的所有字段的值。在Delphi中使用一个对象的唯一方法就是使用对象引用。一个对象引用通常以一个变量的形式存在,但是也有函数或者属性返回值的形式。类同样是一个独立的实体(与Java中的类似,但与C++中的不同)。在Delphi中,类表现为内存中一张只读的表,表中存放着指向该类的虚方法的指针以及其他许多信息。一个类引用(Class reference)就是指向该表的一个指针。类引用最常见的用法是创建一个对象或者用来测试一个对象引用的类型,也可以在其它许多场合使用。比如,传递类引用给某个例程或者从一个函数中返回一个类引用。类引用的类型称为元类(metaclass)

    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;type
      TMainForm = class(TForm)
      private
        { Private declarations }
      public
        { Public declarations }
      end;  TA = class
      public
        a, b: Integer;
        constructor Create;
        class procedure Show;
      end;
    var
      MainForm: TMainForm;implementation{$R *.dfm}{ TA }constructor TA.Create;
    begin
      a := 23;
      b := 24;
    end;class procedure TA.Show;
    begin
      ShowMessage(IntToStr(a));  
    end;end.class procedure TA.Show;
    begin
      ShowMessage(IntToStr(a));  
    end;
    无法编译
    错误提示是在Show里无法访问a,
    因为在一般的类的过程或函数里访问数据成员是通过
    self+数据成员的偏移量来访问的
    这里的self既上面说的对象引用,而a的偏移量是4(去掉前面的vptr)
    而在类方法里也有self,只不过这个self是上面说得类引用,而类引用+4
    访问的东西根本就不是a了,所以编译不通过,
    而且在这个类方法里也只能调用该类的类方法,而对于构造函数
    在抄一下<<delphi技术手册>>上的话构造器是对象方法和类方法的混合体。你可以使用一个对象引用或者一个类引用来调用它。Delphi会传递一个附加的隐含的参数来指示它如何被调用。假如使用一个类引用来调用构造器,Delphi会调用类的NewInstance方法以获得该类的一个新的实例。然后,构造器继续处理并且初始化对象。构造器自动引入一个try-except模块,当构造器中触发异常时,Delphi将自动调用析构器。使用对象引用来调用构造器时,Delphi不会引入try-except块,也不会调用NewInstance方法。相反,它象调用普通方法一样调用构造器。这个特性允许你调用继承的构造器而无需增加额外的内存开销在继续贴一段type
      TSomething = class
        procedure DoSomething;
      end;
    var
      Ref: TSomething;
    begin
      Ref := TSomething.Create;
      Ref.DoSomething;
      Ref.Free;
    end;
    //在构造器中被隐藏代码类似于这样:
    function TSomething.Create(IsClassRef: Boolean): TSomething;
    begin
      if IsClassRef then
      try
        //获得新的对象实例
        Self := TSomething.NewInstance;
     
        //NewInstance初始化对象,功能与InitInstance类似。假如你覆盖了NewInstance,那么,
    //不要调用inherited NewInstance,而应当调用InitInstance。
    //这个调用正如下面所示,因此你可以知道究竟发生了什么,
    //但是请记住通常Delphi实际上并不调用InitInstance。
        InitInstance(Self);
     
    //做构造器真正要做的工作,无需用到类引用。
    //注意,Delphi并不真的对构造器进行递归调用。
        Self.Create(False);
     
        Self.AfterConstruction;
      except
    //若有任何异常发生,Delphi自动调用对象的析构器。
        Self.Destroy;
      end
      else
        Self.Create(False);
      Result := Self;
    end;
     
    //构造器中被隐藏的代码类似于这样:
    procedure TSomething.Destroy(Deallocate: Boolean);
    begin
      if Deallocate then
        Self.BeforeDestruction;
     
      // Delphi并不真的递归调用析构器,但这里是析构器真正发生作用的地方。
      Self.Destroy(False);
     
      if Deallocate then
      begin
    // Delphi并不真的调用CleanupInstance而是调用FreeInstance来做清理的工作。
    // 假如覆盖了FreeInstance,不要调用inherited FreeInstance,而应当调用CleanupInstance
    // 来清理字串、动态数组以及可变类型字段。
        Self.CleanupInstance;
    //调用FreeInstance来释放对象占用的内存。
        Self.FreeInstance;
      end;
    end;由此当调用TSomething.Create,是由类引用调用的,而经过编译器对于构照函数的一些操作,分配对象内存,初始化对象实例,
    然后
    Self.Create(False);
    这时self为对象引用
    这个构造函数也就是上面说的通过对象引用来调用的,所以可以正确的访问
    类的数据成员这章是<<delphi技术手册>>上的对象模型上的内容,我已放到
    http://www.huachu.com.cn/bbs/index.asp的开发那个论坛上,
    其实也是从别的地方抄来的,感觉很好,所以放上去了
    也顺便做个广告,欢迎过去看看,
    呵呵