- サブクラスは、スーパークラスにある定義を再定義することを
避ける便利なメカニズムである。
- 以下の定義を考える。
var myCell: InstanceTypeOf(cell):=new cell;
var myReCell:InstanceTypeOf(reCell):=new reCell;
procedure f(x: InstanceTypeOf(cell)) is ... end;
- また、上の定義のスコープ内で以下のコード断片を考える。
myCell := myReCell;
f(myReCell);
- 両コードとも Pascal のような言語では illegal である。オブジェクト指向
言語では、以下でいう (サブタイプ) polymorphism により、 legal となる。
もし c' が クラス c のサブクラスであり、
o' が c' のインスタンスの時、 o' はクラス c の
インスタンスとなる。
- タイプチェッカの立場からは以下のようになる。
(1) もし c' が c のサブクラスならば
o':InstanceTypeOf(c') そのため o':InstanceTypeOf(c)。
- サブタイプ関係()(反射、推移律が成立)を定義する( InstanceType
に対して)。
(3)
ならば
が
のサブクラスであることが必要十分。
- (2) と (3) から (1) を導くことができる。
- (2) を subsumption といい「サブタイプ関係の性質」である。
「値は、タイプ から に subsume された」という。
- (3) は、(あえていうならば) 「サブクラスはサブタイプである」ということが
できる。また、「継承はサブタイプである」という特性ということもできる。
より最近のクラスベース言語では、「継承はサブタイプでない」を適用した
アプローチもある(後述)。
- subsumption の導入により、メソッド呼び出しの意味を再考察しなければ
ならない。
procedure g(x: InstanceTypeOf(cell)) is
x.set(3);
end;
g(myReCell);
- の呼び出し時に x.set(3) の意味を決定しなければならない。
の(宣言時の)タイプは、 InstanceTypeOf(cell)、値は myReCell
(クラス reCell のインスタンス)。メソッド set は、
クラス reCell の中で override されているので、以下の 2 つの可能性
がある。
静的 dispatch: x.set(3) は cell の
set を実行する。
動的 dispatch: x.set(3) は reCell の
set を実行する。
- 静的 dispatch では、コンパイル時の( xの) 値をもとにしている。
- 動的 dispatch では、実行時の値をもとにしている。
- InstanceTypeOf(reCell) は、 g(myReCell) 呼び出し時の
「真のタイプ」であるという。
- 動的 dispatch は、全てのオブジェクト指向言語で採用されている。
各オブジェクトは自立的に、どのように振る舞うかを知っており、
コンテキストではオブジェクトを examine する必要がなく、
適用すべき演算を決定する。
- 動的 dispatch での興味深い結論として、「subsumption は、
オブジェクトに対して、実行時の影響ははない」ことである。例えば、
InstanceTypeOf(reCell) から InstanceTypeOf(cell) への
subsumption は、付加 attribute を切り捨てた ( backup と restore)
「強制」であり、動的 dispatched 呼び出し は fail する。