Delphi 中友元问题:请高手指点迷津,多谢了。

gold_future 2003-10-16 04:54:15
看下列代码:
//*************************************************************
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 同在一个单元。所以我想书上说法不正确,
但是 上述问题应怎样解决?





...全文
73 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
阿发伯 2003-10-18
  • 打赏
  • 举报
回复
虽然楼主已经揭帖,但我还得说一句,这个问题不是友元问题,所谓友元类,必须是两个类之间的关系,TComponent和TComponent是两个不同的类吗?显然不是,所以楼主的问题只能解释为一个类对自身的实例引用,对自身的实例引用当然可以访问其私有成员。这个问题在C++的操作符重载中经常见到,因为在C++中的友元关系必须用关键字定义,所以很明确,也没有听说或在那本书上看到这是个友元问题,只是解释为“一个类对自身的实例引用”。所谓“自己和自己肯定是友员”的解释绝对是荒唐的,说“自己和自己类似友元关系”到可以说得过去。
majorsoft 2003-10-17
  • 打赏
  • 举报
回复
看来除楼主外,大家搞错了self的概念
非类方法中的self引用的是调用它的对象!
请看:
AOwner.InsertComponent(Self);
self引用的“待创建的对象” 。

AComponent.FOwner := Self;
中的self是引用的“AOwner对象”,即“宿主对象”!
这个是AComponent类的引用,自己和自己当然是友员了!
至于他的派生类中是不是友员的问题,我想是派生类中包含了TComponent的成分.
而TComponent的成分当然和TComponent是友员关系。在C++中,我们不是可以定义某个数据成员是另外一个类的友员吗?
无聊的小船 2003-10-17
  • 打赏
  • 举报
回复
up
A_ZHU 2003-10-17
  • 打赏
  • 举报
回复
AOwner.InsertComponent(Self);晕过来了!
FrameSniper 2003-10-17
  • 打赏
  • 举报
回复
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;




railgunman 2003-10-17
  • 打赏
  • 举报
回复
d
gold_future 2003-10-17
  • 打赏
  • 举报
回复
还没理解
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 有何意义呢?
gold_future 2003-10-17
  • 打赏
  • 举报
回复
我理解了:
(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 数据成员这一说法.

结贴了。

FrameSniper 2003-10-17
  • 打赏
  • 举报
回复
哦?Sorry,我没有看清你的题目,原来你问的是最后一句

自己和自己肯定是友员,这个解释非常到位,不知道楼主还有什么疑惑?


gold_future 2003-10-17
  • 打赏
  • 举报
回复
我觉的 majorsoft(major) 说得有一定道理,我只知道在c++ 中 有友元类, 友元函数,还没有见过友元数据成员,今天晚上回去杳杳书。

to : FrameSniper(§绕瀑游龙§)
我明白你的意思了,但你还没理解我的意思。
对于语句“AComponent.FOwner := Self ;”
我的意思是 语句等号左边(AComponent.FOwner)是违反的返问规则。FOwner 是私有的。
insert是在“宿主对象”执行的。
而FOwner是“将创建对象”的私有成员。只能通过“将创建对象”的公共方法访问。
truezerg 2003-10-16
  • 打赏
  • 举报
回复
看这三句更清楚

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;

明白了? 不是“待创建的对象”
FrameSniper 2003-10-16
  • 打赏
  • 举报
回复
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;”是不正确的,这里访问的是容器的私有数据成员,而不是楼主所说的“将要建的对象”的私有数据成员!所以,这里楼主理解错误!

另外,书上的友元的定义没有错误!呵呵....

阿发伯 2003-10-16
  • 打赏
  • 举报
回复
我想搂主可能把概念搞错了,下面的AComponent是TComponent类型,也就是被定义的类(TComponent)对自己的一个实例引用,而不是友元问题。

procedure TComponent.Insert(AComponent: TComponent);
begin
if FComponents = nil then FComponents := TList.Create;
FComponents.Add(AComponent);
AComponent.FOwner := Self;
end;
leapmars 2003-10-16
  • 打赏
  • 举报
回复
又是一个刨根问底的!跟 FS 一样! ^_^
aiirii 2003-10-16
  • 打赏
  • 举报
回复
可在該單元聲明一個新的class, 繼承你要當做 友元的那個class!!!
FrameSniper 2003-10-16
  • 打赏
  • 举报
回复
回家帮你看看,这个问题偶有兴趣,呵呵!
Alanwn 2003-10-16
  • 打赏
  • 举报
回复
up先

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧