返回介绍

6.2 方法查找

发布于 2025-02-20 00:17:08 字数 3182 浏览 0 评论 0 收藏 0

当给对象发送消息时,我们在它的类中查找实现此消息的方法,然后调用之。反映到 CLASS 宏的定义中就是:

[(invoke)
 (if (assoc (second vals) methods)
     (apply ((cdr (assoc (second vals) methods)) (first vals)) (cddr vals))
     (error "message not understood"))]

有了继承,在对象收到一个在其类中找不到方法的消息时,我们可以在超类中寻找方法,并依此类推。首先, invoke 协议需要修改,将其分成两步:第一步是 lookup (查找),包括当前类中没有找到方法时在超类中进行查找,第二步是实际的 invoke 步骤。

(defmac (CLASS extends superclass
               ([field f init] ...)
               ([method m params body] ...))
  #:keywords field method extends
  #:captures self ? !
  (let ([scls superclass]
        (methods
         (local [(defmac (? fd) #:captures self
                   ((obj-class self) 'read self 'fd))
                 (defmac (! fd v) #:captures self
                   ((obj-class self) 'write self 'fd v))]
           (list (cons 'm (λ (self)
                            (λ params body))) ...))))
    (letrec ([class (λ (msg . vals)
                      (case msg
                        ....
                        [(invoke)
                         (let ((method (class 'lookup (second vals))))
                           (apply (method (first vals)) (cddr vals)))]
                        [(lookup)
                         (let ([found (assoc (first vals) methods)])
                           (if found
                               (cdr found)
                               (scls 'lookup (first vals))))]))])
      class)))

CLASS 语法抽象扩展了,加了 extends 子句(这是类定义中新的关键字)。试用这个抽象之前,我们需要在树的顶部定义一个 类,以终结方法查找的过程。如下的 Root 类就可以:

(define Root
  (λ (msg . vals)
    (case msg
      [(lookup) (error "message not understood:" (first vals))]
      [else     (error "root class: should not happen: " msg)])))

Root 直接实现为函数而不使用 CLASS 形式,所以我们无需指定它的超类(它也没有)。如果收到 lookup 消息,它会给出消息无法理解的错误。请注意,在此系统中,除了 lookup 以外的任何消息发送到根类都是错误。

来看一个非常简单的类继承的例子:

(define A
  (CLASS extends Root ()
         ([method foo () "foo"]
          [method bar () "bar"])))
(define B
  (CLASS extends A ()
         ([method bar () "B bar"])))

> (define b (new B))
> (-> b foo)
"foo"
> (-> b bar)
"B bar"

看起来都对了:向 B 发送其不理解的消息效果正如预期,并且发送 bar 的结果是 B 中调整过而不是 A 中的方法被执行。换一种说法,方法调用被正确的 延迟绑定 (late binding)。我们说, B 中的 bar 方法 覆盖 (override)了 A 中定义的同名方法。

再来看个稍微复杂一点的例子:

> (define p (new Point))
> (-> p move 10)
> (-> p x?)
10

来试试 ColorPoint

> (define cp (new ColorPoint))
> (-> cp color! 'red)
> (-> cp color?)
'red
> (-> cp move 5)
hash-ref: no value found for key
  key: 'x

发生了什么?看来,我们不能使用 ColorPointx 字段。好吧,我们还没有讨论过在继承中如何处理字段。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文