3.3 継承を使用するPL/SQLでのオーバーロードの使用

オーバーロードを使用すると、サブタイプの値を仮パラメータ、つまりスーパータイプに代入できます。この機能を代入性といいます。

オーバーロードおよび代入性については、次のルールがあります。

代入のルール

オーバーロードされたプロシージャの複数のインスタンスがプロシージャ・コールに一致する場合、次の代入ルールによって、コールされるプロシージャが判断されます。

  • オーバーロードされたプロシージャのシグネチャの唯一の違いが、一部のパラメータが同じスーパータイプ・サブタイプ階層のオブジェクト・タイプである場合、最も近い一致が使用されます。最も近い一致とは、サブタイプとスーパータイプの間の継承の深さによって判断され、少なくともすべてのパラメータが他のオーバーロードされたインスタンスと同程度に近く、少なくとも1つのパラメータがより近いことをいいます。

  • オーバーロードされた2つのメソッドのインスタンスが一致したが、1つ目のオーバーロードされたプロシージャにおいていくつかの引数の型が近く、2つ目のプロシージャにおいて他の引数の型が近い場合、セマンティック・エラーが発生します。

  • オブジェクト型階層内でいくつかのパラメータの位置が異なり、かつ他のパラメータはデータ型が異なるために暗黙的な変換が必要になる場合も、セマンティック・エラーが発生します。

3.3.1 継承によるPL/SQLファンクションの解決

継承によるPL/SQLファンクションの解決では、代入のルールに従います。

例3-9では、super_tから始まる3つのレベルを持つ型階層を作成します。ファンクションのオーバーロードされたインスタンスが2つ含まれるパッケージがあります。これらのインスタンスは、型階層内の引数型の位置以外は同じです。起動では、型final_tの変数を宣言してから、オーバーロードされたファンクションをコールします。

階層内でsub_tsuper_tよりもfinal_tに近いため、実行されるファンクションのインスタンスは、sub_tパラメータを受け入れるインスタンスです。これは、代入のルールに基づいたものです。

コールするインスタンスはコンパイル時に決定されるため、渡された引数もfinal_tであったという事実は無視されることに注意してください。宣言がv super_t := final_t(1,2,3)であれば、引数がsuper_tのオーバーロードされたファンクションがコールされます。

例3-9 PL/SQLファンクションと継承の解決

CREATE OR REPLACE TYPE super_t AS OBJECT
  (n NUMBER) NOT final;
/
CREATE OR REPLACE TYPE sub_t UNDER super_t
  (n2 NUMBER) NOT final;
/
CREATE OR REPLACE TYPE final_t UNDER sub_t
  (n3 NUMBER);
/
CREATE OR REPLACE PACKAGE p IS
   FUNCTION func (arg super_t) RETURN NUMBER;
   FUNCTION func (arg sub_t) RETURN NUMBER;
END;
/
CREATE OR REPLACE PACKAGE BODY p IS
   FUNCTION func (arg super_t) RETURN NUMBER IS BEGIN RETURN 1; END;
   FUNCTION func (arg sub_t) RETURN NUMBER IS BEGIN RETURN 2; END;
END;
/

DECLARE
  v final_t := final_t(1,2,3);
BEGIN
  DBMS_OUTPUT.PUT_LINE(p.func(v));  -- prints 2
END;
/

3.3.2 継承によるPL/SQLファンクションの動的解決

継承によるPL/SQLファンクションの動的解決では、代入のルールに従います。

「継承を使用するPL/SQLでのオーバーロードの使用」を参照してください

例3-10では、ファンクションは型階層のメンバー・ファンクションをオーバーライドしているため、コールするインスタンスは実行時に決定されます。これは、「動的メソッド・ディスパッチ」で説明されている動的メソッド・ディスパッチです。

vsuper_tのインスタンスですが、final_tの値がvに割り当てられているため、代入のルールに従ってファンクションのsub_tインスタンスがコールされます。

例3-10 PL/SQLファンクションと継承の動的解決

-- Perform the following drop commands if you created these objects in Ex. 3-9
-- DROP PACKAGE p;
-- DROP TYPE final_t;
-- DROP TYPE _sub_t;
-- DROP TYPE super_t FORCE;
CREATE OR REPLACE TYPE super_t AS OBJECT
  (n NUMBER, MEMBER FUNCTION func RETURN NUMBER) NOT final;
/
CREATE OR REPLACE TYPE BODY super_t AS
 MEMBER FUNCTION func RETURN NUMBER IS BEGIN RETURN 1; END; END;
/
CREATE TYPE sub_t UNDER super_t
  (n2 NUMBER,
   OVERRIDING MEMBER FUNCTION func RETURN NUMBER) NOT final;
/
CREATE OR REPLACE TYPE BODY sub_t AS
 OVERRIDING MEMBER FUNCTION func RETURN NUMBER IS BEGIN RETURN 2; END; END;
/
CREATE OR REPLACE TYPE final_t UNDER sub_t
  (n3 NUMBER);
/

DECLARE
  v super_t := final_t(1,2,3);
BEGIN
  DBMS_OUTPUT.PUT_LINE('answer:'|| v.func); -- prints 2
END;
/