「オブジェクト指向プログラミング」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
→‎メタクラス: クラスベース継承において、(インスタンスとしての)クラスもまたオブジェクトとして扱おうとした時、クラスの属するクラス(=メタクラス)が仮定されます。 では、メタクラスの属するクラスは?・・・メタクラス自身もメタクラスのインスタンスです。 ここで「有向無サイクルグラフ」の仮定が壊れます。 メタクラスの位置づけは言語によって様々で、初期のSmalltalk(Smalltalk-76)では、Classという単一のクラスがメタクラスでしたが、Smalltalk(Smalltalk-80)では、すべてのクラスに独自のメタクラスがあり、それぞれのメタクラスは単一のMetaclass classのインスタンスです(メタのメタのメタ…の無限の連鎖は避けている)。少し想像すると判るように、メタクラスの操作は概念上のシフトが必要で、微妙で煩雑なものとなりがちです(パラドクスと言ってもいい)。 このような複雑さを解決するために、「クラスなんてなかった、インスタンスはインスタンスの複製によって生成して、複製を新たに修飾し目的を達成する」というアプローチが生まれました。
タグ: 2017年版ソースエディター
89 行
たとえば、Employee クラスのオブジェクトは、"first_name" や "position" といった自身のインスタンス変数に加えて、Address クラスのオブジェクトを (直接またはポインタを介して) 含むことができます。
=== 継承 ===
オブジェクト指向プログラミングをサポートしてにおる言語はほとんどあるオブジェクトやクラスを別場合、クラス(クラスベース継承)やオブジェクト(プロトタイプベース継承)サポスにして、同様の実装を保持する仕組みのことを「継承」といいます。
 
これにより、クラスを「~である」という関係を表す階層に配置することができます。
例えば、Employee==== クラスは Person クラベー継承しています。 ====
クラスベース継承では、スーパークラスと呼ばっる既存のクラスから新しいクラス(サブクラス)を派生させ、クラスの階層を形成します。継承によって生成されたオブジェクト(派生オブジェクト)は、スーパークラス(あるいはプロトタイプ)のコンストラクタ、デストラクタ、オーバーロード演算子、フレンド関数を除き、親オブジェクトのすべてのプロパティと動作を獲得します。
スーパークラス(継承元)で利用できるデーターやメソッドは、サブクラス(継承先)にも同じ名前で表示されます。
サブクラスは、スーパークラスで定義されたメソッドを[[#オーバーライド|オーバーライド]]できます。
例えば、Person クラスは、"first_name" と "last_name" という変数を "make_full_name()" というメソッドで定義しています。
継承によって、プログラマは既存のクラスの上にクラスを作成し、同じ振る舞いを維持しながら新しい実装を指定し(インターフェースの実現)、コードを再利用し、パブリッククラスやインターフェースによって元のソフトウェアを独自に拡張することができます。継承によるクラスの関係は、有向無サイクルグラフを生み出します。
これらはEmployeeクラスでも使用可能で、Employeeクラスには変数 "position "と "salary "が追加されるかもしれません。
 
この手法では、同じプロシージャやデータ定義を簡単に再利用できるだけでなく、現実世界の関係を直感的に反映できる可能性があります。
===== スーパークラス =====
開発者は、データベースのテーブルやプログラミングのサブルーチンを利用するのではなく、ユーザーがより慣れ親しんでいるであろうオブジェクト、つまりアプリケーション・ドメインのオブジェクトを利用します。
スーパークラスは、クラスベース継承における継承元となるクラス。
サブクラスは、スーパークラスで定義されたメソッドを[[#オーバーライド|オーバーライド]]できます。
===== サブクラス =====
サブクラスは、クラスベース継承における継承先となるクラス。
 
===== メタクラス =====
クラスベース継承において、(インスタンスとしての)クラスもまたオブジェクトとして扱おうとした時、クラスの属するクラス(=メタクラス)が仮定されます。
では、メタクラスの属するクラスは?・・・メタクラス自身もメタクラスのインスタンスです。
ここで「有向無サイクルグラフ」の仮定が壊れます。
メタクラスの位置づけは言語によって様々で、メタクラスを持たない<!--自称-->オブジェクト指向言語もあります。
初期のSmalltalk(Smalltalk-76)では、Classという単一のクラスがメタクラスでしたが、Smalltalk(Smalltalk-80)では、すべてのクラスに独自のメタクラスがあり、それぞれのメタクラスは単一のMetaclass classのインスタンスです(メタのメタのメタ…の無限の連鎖は避けている)。少し想像すると判るように、メタクラスの操作は概念上のシフトが必要で、微妙で煩雑なものとなりがちです(パラドクスと言ってもいい)。
このような複雑さを解決するために、「クラスなんてなかった、インスタンスはインスタンスの複製によって生成して、複製を新たに修飾し目的を達成する」というアプローチが生まれました。これが、[[#プロトタイプベースのオブジェクト指向|プロトタイプベースのオブジェクト指向]]/[[#プロトタイプベース継承|プロトタイプベース継承]]です(プロトタイプベースはインスタンスベースとも呼ばれます)。
 
==== プロトタイプベース継承 ====
プロトタイプベース継承では、プロトタイプと呼ばれる既存のオブジェクトを複製し新しいオブジェクトを派生させ、プロトタイプの階層を形成します。複製されたオブジェクト(派生オブジェクト)は、プロトタイプへの参照を持ち、それを通じてプロトタイプのすべてのプロパティ(データプロパティと関数プロパティ)を獲得します。
派生オブジェクトは、プロトタイプで定義されたプロパティを[[#オーバーライド|オーバーライド]]もできます。
継承によって、プログラマは既存のオブジェクトから新しいオブジェクトを生成し、同じ振る舞いを維持しながら新しい実装を指定し(インターフェースの実現)、コードを再利用し、パブリックオブジェクトやインターフェースによって元のソフトウェアを独自に拡張することができます。継承によるオブジェクトの関係は、有向無サイクルグラフを生み出します。
 
===== プロトタイプ =====
プロトタイプは、プロトタイプベース継承における継承元となるオブジェクト。
 
===== 派生オブジェクト =====
派生オブジェクトは、プロトタイプベース継承における継承先となるオブジェクト。
派生オブジェクトも、プロトタイプになることができるので、ことさら派生を強調せず、単にオブジェクトと称されます。
 
===== プロトタイプ チェーン =====
すべてのオブジェクトは、プロトタイプへの参照を保持しており、プロトタイプもまたオブジェクトなので、プロトタイプは単方向リストになります。プロトタイプを手繰ることによる単方向リストを、プロトタイプ チェーン( ''prototype chain'' )と呼びます。プロトタイプ チェインを遡ると、自分自身をプロトタイプにする特別なオブジェクトに行き着きます。このオブジェクトが始祖のオブジェクトで、JavaScriptでは Object、Lua では Table です。
オブジェクトのプロパティを参照する時、まずオブジェクト自身のスロットにプロパティ キーが無いかしら調べ、あればプロパティ 値を返します。なかった時は、1つプロトタイプ チェインを遡り、探しみつかればその値を返します。始祖のオブジェクトまで遡っても見つからなければ「存在しないプロパティの参照」とします。
プロパティの[[#オーバーライド|オーバーライド]]の実装は、このようにプロトタイプ チェーンによって実現しています。
 
=== 多重継承 ===
一部の言語では多重継承が可能ですが、オーバーライドの解決が複雑になる可能性があります。
131 ⟶ 159行目:
 
=== ポリモーフィズム ===
ポリモーフィズムの一種であるサブタイピングとは、呼び出したコードが、サポートされている階層のどのクラスを操作しているのか、スーパークラスなのか、サブクラスなのかを問わないことです。
一方で、継承階層内のオブジェクト間では、同じ操作名でも動作が異なる場合があります。