3.7. クラスの変更 (1)

この章では二つのトピックをざっと扱います。既存のクラスの再定義と、インスタンスのクラスを別のクラスに変更してしまうことです。どちらのトピックも表面をなぞるだけですが、何でもできる分だけ奥が深いことを知るには十分です。

クラスを再定義するには、新しい defclass フォームを評価するだけです。
defclass は古い定義を捨て、既存のクラスオブジェクトを更新し、すべてのインスタンスのクラスも(そのサブクラスも再帰的に)更新し、新しい定義を反映させます。次の例を見てください。

; インスタンス、クラス、スロットの確認。
CL-USER 46 > (list Eric (class-of Eric) (slot-exists-p Eric 'has-tail-p))
(#<FIGURINE-AARDVARK 2112B44C>
 #<STANDARD-CLASS FIGURINE-AARDVARK 2150938C>
 NIL)
 
; スーパークラスを再定義する。
CL-USER 47 > (defclass animal ()
               ((legs :reader leg-count :initarg :legs)
                (has-tail-p :reader has-tail-p :initform t)
                (comes-from :reader comes-from :initarg :comes-from)))
#<STANDARD-CLASS ANIMAL 2150BA0C>
 
; 既存のインスタンスとクラスが更新され、新しいスロットが増えている。
CL-USER 48 > (list Eric (class-of Eric) (slot-value Eric 'has-tail-p))
(#<FIGURINE-AARDVARK 2112B44C>
 #<STANDARD-CLASS FIGURINE-AARDVARK 2150938C>
 T)
 
CL-USER 49 >

アプリケーションの動作中もクラスを再定義でき、同様の方法で関数も再定義できます。強力なことに、たとえアプリケーションの開発中でも再定義できます。例えば、クラスを定義したときには考えてなかったスロットやスーパークラスを追加できます。しかも defclass 以外には再コンパイルも必要なしに、既存のオブジェクトを捨てる必要もなしにです。