苛评VCL: 接口与TObject

在李维的《inside VCL》中详细描述了VCL中TObject的地位。是的Borland的工程师们有心将Delphi语言做成pure language。所以你几乎可以看到TObject的所有pure pascal的实现。

更重要的,你应该会发现。Delphi将代码的所有运行机制都暴露在我们面前。这也就是Delphi的TObject和C++中的Object以及C#的Object有很大不同的地方。

Delphi将整个语言的机制都在TObject上实现了。消息机制、接口机制、面向对象机制(多态)等等你都可以从TObject的实现代码中看到运行的全部流程。

不管TObject如何优秀,可是TObject正如Borland一样,在它身上总是看到受制于MS的影子。特别是接口机制。我有两点认为TObject的设计不好。

  1. 对象指针和接口指针并不是同一个地址
  2. 对象和接口不可以混用

先说说我第一个不满意的地方。说是第一,并不表示是“最”的意思。只是代表“最先”的意思。

在Delphi的TObject中,类在实现了接口之后,其创建的实例中,对象指针和接口指针并不是同一个地址。这个可能大家没有注意到,但是主要通过简单的例子(取两个指针的地址)就可以发现这个现象。

你可能不会在意这个差异。是的,其实也没什么,不是同一个地址,代码照样可以工作。在对象的内存实例模型中,接口的指针直接存储在属性后面(如果存在继承,可能会出现交错的)。因为TObject设计的时候,两个地址不在一起,那么就存在两个问题:

  • 如果从对象转换到接口
  • 如何从接口转换到对象

稍微知道对象模型的人,就应该知道对象调用虚拟方法表的过程。只有对象指针可以指向VMT。另外,在接口访问方法的实现代码的时候,也需要传入对象指针。这是为什么?我们知道,一个对象的方法中,有一个隐含的指针,我们一般称它为Self指针。只要不是class function,那么这个Self指针就是指向对象实例的指针。所以在代码的调用过程中,必然有这个转换。

TObject提供的AS操作,可以完成第1个转换,但是可惜的是,TObject并没有提供一个公开的方法来负责第2个转换。这是我认为TObject在这方面设计不好的原因。(JCL代码库中有第2个转换的代码)

第二个我不满意的地方就是TObject在生存期管理上,没有做到和接口一致。我相信这也是许多使用Delphi接口的同志们一致的想法。虽然我们现在看到Java和C#都已经做到这点,可不能不指出的是,在Delphi中,对象和接口不可以混用!

我并不是奢求TObject的生存期可以自管理。毕竟,我还是习惯了“谁创建谁释放”的规则。可是一旦到了接口和对象混合使用的时候,就发生了问题。

这虽然可以解释为接口是Delphi为了迎合COM而后加上的。我们今天却应该来设计一下一种规则,来解决接口混用的问题。我认为可以有一种简单的方式:TObject在Free的时候,发现其接口引用计数不为0的时候,不会Destroy。

目前我们无法做到这点,这是因为Destroy是Delphi默认做的,也就是说,只要调用了Free方法,Destroy必然发生。我们无法完美地改变这个现实。也正因为此,我才认为必须在设计TObject的时候,将这个考虑进去!

OK。尝试重新审视VCL中的各个基础类,其实有点大胆。所以用“苛评”这个词来做标题,表明这完全是我的苛刻,VCL的设计是非常棒的。不过也算是我使用6年Delphi的一点回报吧。以后还会继续苛评其他类。希望大家继续关注。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 30
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值