inheritance - CLOS:如何调用一个不太具体的方法?

标签 inheritance methods common-lisp reusability clos

有一个通用方法,比如 incx . incx有两个版本.一种专攻类型 a ,还有一个专门针对类型 b .类型 ba 的子类.你得到一个类型为 b 的对象,派生类型 - 但您想调用专门用于类型 a 的方法.如果还没有专门用于类型 b 的同名方法,您可以轻松地做到这一点。 ,不过唉,居然有这样的方法。

那么如何调用专用于类型 a 的方法?在这种情况下?

(defclass a () ((x :accessor x :initform 0)))
(defclass b (a) ((y :accessor y :initform 0)))

(defgeneric inc (i))

(defmethod inc ((i a)) (incf (x i)))
(defmethod inc ((i b)) (incf (y i)))

(defvar r (make-instance 'b))

正如 CLOS 所 promise 的,这调用了最专业的方法:
* (inc r) 
* (describe r)
    ..
  Slots with :INSTANCE allocation:
    X  = 0
    Y  = 1

但是在这种特殊情况下,(不是一般情况下)我想要的是访问不太专业的版本。像这样说:
(inc (r a)) ; crashes and burns of course, no function r or variable a
(inc a::r)  ; of course there is no such scoping operator in CL

我看到了 call-next-method函数可以从一个专门的方法中使用来获得下一个不那么专门的方法,但这不是这里想要的。

在删除的代码中,我确实需要类似于 call-next-method 的内容。 ,但用于调用补充方法。我们不需要在下一个不太专业的类中调用同名的方法,而是需要调用它的补充方法,它具有不同的名称。补充方法也是专门的,但调用这个专门的版本不起作用 - 与 call-next-method 的原因大致相同。可能被包括在内。专用于父类(super class)的所需方法并不总是具有相同的名称。
(call-next-method my-complement)  ; doesn't work, thinks my-complement is an arg

这是另一个例子 .

有一个描述电子特性的基类和一个描述“奇怪电子”特性的派生类。专门针对奇怪电子的方法希望调用专门针对电子的方法。为什么?因为这些方法为程序做了正常的电子部分工作。奇怪电子的非电子部分几乎是微不足道的,或者更确切地说,如果它没有复制电子代码:
(defgeneric apply-velocity (particle velocity))
(defgeneric flip-spin (particle))

;;;; SIMPLE ELECTRONS

(defclass electron ()
  ((mass
      :initform 9.11e-31
      :accessor mass)
   (spin
      :initform -1
      :accessor spin)))

(defmacro sq (x) `(* ,x ,x))

(defmethod apply-velocity ((particle electron) v)
  ;; stands in for a long formula/program we don't want to type again:
  (setf (mass particle) 
        (* (mass particle) (sqrt (- 1 (sq (/ v 3e8)))))))

(defmethod flip-spin ((particle electron))
  (setf (spin particle) (- (spin particle))))

;;;; STRANGE ELECTRONS

(defclass strange-electron (electron)
  ((hidden-state
      :initform 1
      :accessor hidden-state)))

(defmethod flip-spin ((particle strange-electron))
  (cond
    ((= (hidden-state particle) 1)
     (call-next-method)

     ;; CALL ELECTRON'S APPLY-VELOCITY HERE to update
     ;; the electron. But how???
     )
    (t nil)))

;; changing the velocity of strange electrons has linear affect!
;; it also flips the spin without reguard to the hidden state!
(defmethod apply-velocity ((particle strange-electron) v)
  (setf (mass particle) (* (/ 8 10) (mass particle)))

  ;; CALL ELECTRON'S SPIN FLIP HERE - must be good performance,
  ;; as this occurs in critical loop code, i.e compiler needs to remove
  ;; fluff, not search inheritance lists at run time
  )

这一切都归结为一个简单的问题:

如果定义了更专业的方法,如何调用不太专业的方法?

最佳答案

我更喜欢这里的显式方法:

(defun actually-inc-a (value) (incf (x value)))
(defun actually-inc-b (value) (incf (y value)))

(defmethod inc ((object a)) (actually-inc-a object))
(defmethod inc ((object b)) (actually-inc-b object))

即,将要共享的实现部分放入单独的函数中。
(defun apply-velocity-for-simple-electron (particle v)
  (setf (mass particle) (* (mass particle) (sqrt (- 1 (sq (/ v 3e8)))))))

(defun flip-spin-for-simple-electron (particle)
  (setf (spin particle) (- (spin particle))))

(defmethod apply-velocity ((particle electron) v)
  (apply-velocity-for-simple-electron particle v))

(defmethod flip-spin ((particle electron))
  (flip-spin-for-simple-electron particle))

(defmethod apply-velocity ((particle strange-electron) v)
  (setf (mass particle) (* (/ 8 10) (mass particle)))
  (flip-spin-for-simple-electron particle))

(defmethod flip-spin ((particle strange-electron))
  (when (= (hidden-state particle) 1)
    (call-next-method)
    (apply-velocity-for-simple-electron particle #| Hu? What's the V here? |#)))

鉴于我对电子一无所知,无论是普通的还是奇怪的,旋转的与否,我真的想不出这些基本辅助函数的有意义的名称。但除此之外...

关于inheritance - CLOS:如何调用一个不太具体的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35171694/

相关文章:

python - Django ModelForm继承与Meta继承

c++ - 关于来自 VC12 和 VC14 的 c++ 友元和继承的不同行为

java - javafx中的preferred是什么意思

c++ - 从方法返回内部类时出错(C++)

common-lisp - 为什么 REPL 没有显示函数调用的完整跟踪?

c++ - 带有指向可变模板模板参数的指针的类

java - 避免让构造函数调用构造函数中的第一个语句

c# - 并非所有代码路径都返回一个值,for 循环

Lisp - 检查输入是十进制还是字符串

recursion - Lisp递归混淆