看下列代码:
//*************************************************************
constructor TComponent.Create(AOwner: TComponent);
begin
  FComponentStyle := [csInheritable];
  if AOwner <> nil then AOwner.InsertComponent(Self);
end;
//*************************************************************
procedure TComponent.InsertComponent(AComponent: TComponent);
begin
  AComponent.ValidateContainer(Self);
  ValidateRename(AComponent, '', AComponent.FName);
  Insert(AComponent);
  AComponent.SetReference(True);
  if csDesigning in ComponentState then
    AComponent.SetDesigning(True);
  Notification(AComponent, opInsert);
end;
//*************************************************************
procedure TComponent.Insert(AComponent: TComponent);
begin
  if FComponents = nil then FComponents := TList.Create;
  FComponents.Add(AComponent);
  AComponent.FOwner := Self;
end;在“将要创建的对象 ”的构造函数执行时,会向“宿主对象”发消息:AOwner.InsertComponent(Self);
“宿主对象”在接到消息时 会调用 “宿主对象”的一个私有方法 
Insert(AComponent);
在 “宿主对象”的方法Insert(AComponent)执行时竞然访问了“将要建的对象”的私有成员AComponent.FOwner := Self;有书上说 当几个类 的声明在同一个单元文件中时 这几个类互为友元。
那么“将要创建的对象”所属的类很能不会与 Tcomponet 同在一个单元。所以我想书上说法不正确,
但是 上述问题应怎样解决?

解决方案 »

  1.   

    可在該單元聲明一個新的class, 繼承你要當做 友元的那個class!!!
      

  2.   

    我想搂主可能把概念搞错了,下面的AComponent是TComponent类型,也就是被定义的类(TComponent)对自己的一个实例引用,而不是友元问题。procedure TComponent.Insert(AComponent: TComponent);
    begin
      if FComponents = nil then FComponents := TList.Create;
      FComponents.Add(AComponent);
      AComponent.FOwner := Self;
    end;
      

  3.   

    To Aiirii  这个楼住的问题和友元没有任何关系!To MaoZeFa
      
      的确,这个楼主的问题不是友元问题,不过这里虽然是对自己实例的一个引用,但也未必这么简单,如下:其实上面三个方法最重要的三句分别是
    1.TComponent构造器中的if AOwner <> nil then AOwner.InsertComponent(Self);
    2.TComponent.InsertComponent中的Insert(AComponent);
    3.TComponent.Insert中的if FComponents = nil then FComponents := TList.Create;仔细看看,很容易看明白,其实这个三个语句组成一个操作链
    1中的Self和2中的AComponent其实是一个对象(对一个连续操作而言),同理2中的Insert(AComponent)前面隐含的Self其实就是3中FComponents前面隐含的Self,所以楼主的最后一个判断----“在 “宿主对象”的方法Insert(AComponent)执行时竞然访问了“将要建的对象”的私有成员AComponent.FOwner := Self;”是不正确的,这里访问的是容器的私有数据成员,而不是楼主所说的“将要建的对象”的私有数据成员!所以,这里楼主理解错误!另外,书上的友元的定义没有错误!呵呵....
      

  4.   

    看这三句更清楚constructor TComponent.Create(AOwner: TComponent);
    begin
      ...
      if AOwner <> nil then AOwner.InsertComponent(Self);  <----  self 是自身
    end;
    procedure TComponent.InsertComponent(AComponent: TComponent); <--- 是上面传进来的那个self
    begin
      ...
      Insert(AComponent); <--- 还是那个self
      ...  
    end;procedure TComponent.Insert(AComponent: TComponent);
    begin
      ...
      AComponent.FOwner := Self;   <--- AComponent 就是 self
    end;明白了?  不是“待创建的对象”
      

  5.   

    还没理解
    to: FrameSniper(§绕瀑游龙§)  
      Insert(AComponent)前面隐含的Self其实就是3中FComponents前面隐含的Self,
      这里访问的是容器的私有数据成员,而不是楼主所说的“将要建的对象”的私有数据成员!  (问1)"FComponents前面隐含的Self" 这句话如何理解? 
       
      (问2)在整个过程中 主要有两个对象在活动 一个是“将要创建的对象”,一个是“宿主对象” 所以应有两个 self 指针。
            第三个函数(insert)中 的AComponent 存放的是一个self指针 
           (是“将要创建的对象”的self指针,不是“宿主对象”的self指针),
      而这句话 AComponent.FOwner := Self 怎么成了 访问容器的么有数据?
      
    to truezerg(赵明宇)  我理解你的意思是说: AComponent 不是“待创建的对象” 
     假如AComponent 是“宿主对象”,那么AComponent.FOwner := Self 有何意义呢?
      

  6.   

    To 楼主
     
    问题1:if FComponents = nil then FComponents := TList.Create;这个话其实就是
    if Self.FComponents = Nil then Self.FComponents := TList.Create;这里省略了Self这个隐含参数!这个参数指定的是当前类方法的当前实例;问题2:你的叙述已经存在问题,我把你写的那三个过程重新给你讲解一边,如下--
    我们假设宿主对象为A,将被创建对象为B//*************************************************************
    constructor TComponent.Create(AOwner: TComponent);  //调用这个过程的情况一般是直接调用B所属类的构造器,如TEdit.Create(Application);
    begin
      FComponentStyle := [csInheritable];  //指定B可被继承      
      if AOwner <> nil then AOwner.InsertComponent(Self);  //将B(这里是Self)插入到A(这里是AOwner)的组件列表中,然后看下面的方法
    end;
    //*************************************************************
    procedure TComponent.InsertComponent(AComponent: TComponent);
    //这里的AComponent为上面的B,InsertComponent为上面A的一个可使用方法
    begin
      AComponent.ValidateContainer(Self);  //检测A(这里是Self)是否是一个有效的容器
      ValidateRename(AComponent, '', AComponent.FName);  //对B检测重命名
      Insert(AComponent);  //将B插入到A中,这里其实是省略了隐含参数Self,然后看下面这个方法
      AComponent.SetReference(True);
      if csDesigning in ComponentState then
        AComponent.SetDesigning(True);
      Notification(AComponent, opInsert);
    end;
    //*************************************************************
    procedure TComponent.Insert(AComponent: TComponent);
    begin
      //这里FComponents前面隐含的Self其实就是上面过程中的A,所以,这里不是访问“将创建对象”的FComponents,而是宿主对象的FComponents,明白?
      if FComponents = nil then FComponents := TList.Create;
      FComponents.Add(AComponent);
      AComponent.FOwner := Self;
    end;
      
      

  7.   

    AOwner.InsertComponent(Self);晕过来了!
      

  8.   

    看来除楼主外,大家搞错了self的概念
    非类方法中的self引用的是调用它的对象!
    请看:
    AOwner.InsertComponent(Self);
    self引用的“待创建的对象” 。

     AComponent.FOwner := Self;
    中的self是引用的“AOwner对象”,即“宿主对象”!
    这个是AComponent类的引用,自己和自己当然是友员了!
    至于他的派生类中是不是友员的问题,我想是派生类中包含了TComponent的成分.
    而TComponent的成分当然和TComponent是友员关系。在C++中,我们不是可以定义某个数据成员是另外一个类的友员吗?
      

  9.   

    我觉的 majorsoft(major) 说得有一定道理,我只知道在c++ 中 有友元类, 友元函数,还没有见过友元数据成员,今天晚上回去杳杳书。to : FrameSniper(§绕瀑游龙§) 
    我明白你的意思了,但你还没理解我的意思。
    对于语句“AComponent.FOwner := Self ;”
    我的意思是 语句等号左边(AComponent.FOwner)是违反的返问规则。FOwner 是私有的。
    insert是在“宿主对象”执行的。
    而FOwner是“将创建对象”的私有成员。只能通过“将创建对象”的公共方法访问。
      

  10.   

    哦?Sorry,我没有看清你的题目,原来你问的是最后一句自己和自己肯定是友员,这个解释非常到位,不知道楼主还有什么疑惑?
      

  11.   

    我理解了:
    (1)insert 方法是声明在 Classes单元 中的一个类的方法;
    (2)insert 方法所问的 私有数据(FOwner)也是在Classes单元定义的。
    (3)insert 可以看作 Classes 单元中 所有定义类的一个友元函数。
    (4)insert 最后被派生类继承了(的确继承了,但是在派生类中不能访问,因为他是私有的),
    (5)insert 是classes中所定义的的类的友元函数 这一点在TComponet的派生类是没有变化的。
    (6)Insert 仅能访问classes中所定义的的类的私有数据,不能访问派生类的私有数据。
    to  majorsoft(major):
    我刚在 msdn中 c++ Reference  中查了一下,C++中没有 friend 数据成员这一说法.结贴了。
      

  12.   

    虽然楼主已经揭帖,但我还得说一句,这个问题不是友元问题,所谓友元类,必须是两个类之间的关系,TComponent和TComponent是两个不同的类吗?显然不是,所以楼主的问题只能解释为一个类对自身的实例引用,对自身的实例引用当然可以访问其私有成员。这个问题在C++的操作符重载中经常见到,因为在C++中的友元关系必须用关键字定义,所以很明确,也没有听说或在那本书上看到这是个友元问题,只是解释为“一个类对自身的实例引用”。所谓“自己和自己肯定是友员”的解释绝对是荒唐的,说“自己和自己类似友元关系”到可以说得过去。