コンテンツにスキップ

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

出典: フリー百科事典『ウィキペディア(Wikipedia)』
削除された内容 追加された内容
たうぇ (会話 | 投稿記録)
Palm1234 (会話) による ID:75324562 の版を取り消し
タグ: 取り消し
(8人の利用者による、間の134版が非表示)
1行目: 1行目:
{{複数の問題
{{複数の問題
|独自研究=2018年2月
|独自研究=2018年2月
|正確性=2019年2月
|出典の明記=2019年2月
|出典の明記=2019年2月
}}
}}
[[ファイル:Object oriented design object.jpg|境界|右|フレームなし|265x265ピクセル]]
{{プログラミング言語|index=おふしえくとしこうふろくらみんく}}
{{プログラミング・パラダイム}}
[[ファイル:Object oriented design object.jpg|境界|右|フレームなし]]
{{Wikibooks|オブジェクト指向|オブジェクト指向}}
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)は、[[オブジェクト指向]]の[[プログラミングパラダイム|考え方]]<ref>コンピュータ・プログラミングのパラダイムについては『新しいプログラミング・パラダイム』などを参照: http://www.kyoritsu-pub.co.jp/bookdetail/9784320024939</ref>を取り入れた[[プログラミング (コンピュータ)|コンピュータプログラミング]]手法である。[[オブジェクト (プログラミング)|オブジェクト]]とは大まかに言うとデータ([[変数 (プログラミング)|変数]]または[[プロパティ (プログラミング)|プロパティ]])とコード([[関数 (プログラミング)|関数]]または[[メソッド (計算機科学)|メソッド]])の複合体を意味しているが、その詳細については様々な解釈が存在する。OOPに基づくプログラムはこの[[オブジェクト (プログラミング)|オブジェクト]]の集合として組み立てられる事になるが、その実装スタイルもまた千差万別である。

'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)とは、互いに密接な関連性を持つ[[変数 (プログラミング)|データ]]([[変数 (プログラミング)|変数]]または[[プロパティ]])と[[サブルーチン|コード]]([[関数 (プログラミング)|関数]]または[[メソッド (計算機科学)|メソッド]])をひとつにまとめて[[オブジェクト (プログラミング)|オブジェクト]]とし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。


オブジェクト指向プログラミングという言葉自体は計算機科学者[[アラン・ケイ]]が作りしたものである。彼は1967公開された[[Simula|Simula67]]の[[クラス (コピュータ)|クラ]]と[[オブジェクト (プログラミング)|オブジェクト]]を備え言語仕様を見た際に''object-orientedという造語を咄嗟に口にしたとされ、その造語は''ケイ自身が1972年から80年にかけて開発た[[Smalltalk]]の言語設計を説明する中で初め用いれて世間にられるようになった。なお[[Smalltalk]]における、あらゆるプログラム内要素をオブジェクトとして扱い、[[メッセージパッシング]]ニケションさせるケイ発案のオブジェクト指向の実践、マシンパワやリソース必要としたため誰もがその恩恵に預かれたわけではなかった。1983年に公開された[[C++]]が契機なりOOPはまた違った角度から注目されるようなった。最終的にこの[[C++]]の設計スタイルが物議を醸ながらもOOPの主流となる到り、同時にOOPの三原則とされる[[カプセル化]]、[[継承 (プログラミング)|継承]]、[[ポリモーフィズム|多態性]]の[[プログラミングパラダイム]]が確立されている
'''[[オブジェクト指向]]'''という用語自体は計算機科学者[[アラン・ケイ]]によって生みされている。1962年公開の言語「[[Simula]]」にインスパイアされケイが咄嗟に口にしたとされるこの造語は、彼が1972年から開発公開を始め[[Smalltalk]]の言語設計を説明する中で発信され1981年頃から知名度を得た。しかしケイが示したオブジェクト指向の要点である[[メッセージパッシング|メッセージング]]の考え方はさほど認知される事はなく、代わりに[[クラス (ンピュータ)|クラス]]と[[オブジェクト (プログラミグ)|オブジェクト]]という仕組みを注目させるだけに留まってる。同時にケイの手から離れたオブジェクト指向は[[抽象デタ型]]中心にした解釈へと推移していき、1983年に計算機科学者[[ビャーネ・ストロヴストルップ]]が公開[[C++]]好評を博したこオブジェクト指向対する世間理解は「[[C++]]」とそのモデルの「[[Simula|Simula 67]]」のスタイルで定着た。それ基づいて[[カプセル化]]、[[継承 (プログラミング)|継承]]、[[ポリモーフィズム]]といった考え方も後年に確立され


== 特徴 ==
== 特徴 ==
プログラミングパラダイムとしてのオブジェクト指向の確立は紆余曲折を経ており(後述)その詳細の解釈も様々であるが、一定の枠組みとなる三つの原則(''fundamental principle'')が存在し、それに従った言語仕様を総体的または部分的に備えたプログラミング言語がオブジェクト指向準拠と判別される。1~3はオブジェクト指向プログラミングの三原則とされるものであり[[C++]]を契機にして提唱された。4を加えて四本の柱(''pillar'')とする考えもある。


=== クラスベースとプロトタイプベース ===
5~7は[[Smalltalk]]が提唱する元祖オブジェクト指向のコンセプトであり、この三者は相互に関連して始めて一つの意味を表現している。その真髄はオブジェクトを媒体にしてコードとデータの融合を目指した高度な抽象化または代数化である。元祖オブジェクト指向は哲学的側面が強いものであり、それを実用的に演繹したものが1~3であると考える事も出来る。
OOPという[[プログラミングパラダイム|パラダイム]]は、[[クラスベース]]と[[プロトタイプベース]]の二つのサブパラダイムに大別されている。クラスベースの代表格は「[[C++]]」「[[Java]]」「[[C Sharp|C#]]」であり、プロトタイプベースの代表格は「[[Python]]」「[[JavaScript]]」「[[Ruby]]」である。前者は[[クラス (コンピュータ)|クラス]]と[[インスタンス]]の仕組みを中心にしており、後者は{{仮リンク|メタオブジェクトプロトコル|en|Metaobject|label=}}の仕組みを基礎にしている。前者は[[静的型付け]]を重視しており、後者は[[動的型付け]]を重視している。2000年代以降になるとプロトタイプベースもクラスの仕組みを積極的に取り入れるようになったので、純粋なプロトタイプベースの存在感は失われつつある。本節でもクラスベースを基準にして説明する。


=== クラスとインスタンス ===
#[[カプセル化]](''encapsulation'')
OOPの要点である[[クラス (コンピュータ)|クラス]]とは、端的に言うと変数と関数をひとまとめにしたものであり、手続きを付けたデータ構造体とも解釈される。コンパイル時定義の静的型付けが普通である。クラスに属する[[変数 (プログラミング)|変数]]はデータメンバまたは'''データ'''と総称され、言語別にフィールド、[[プロパティ (プログラミング)|プロパティ]]、[[属性]]、メンバ変数といった名称になっている。クラスに属する[[関数 (プログラミング)|関数]]はもっぱら'''メソッド'''、メンバ関数、メンバ手続きといった名称になっている。これだけの説明だと[[C言語]]や[[Visual Basic .NET|Visual Basic]]系などの非OOP言語で使用される[[モジュール]]と、OOP言語のクラスは同じものに見えるが双方の間には明確な違いがあり、モジュールに'''抽象'''(''abstraction'')の考え方とその機能を導入したものがクラスである。抽象化のための機能とは後述の[[カプセル化]]、[[継承 (プログラミング)|継承]]、[[ポリモーフィズム]]を指している。
#[[継承 (プログラミング)|継承]](''inheritance'')
#[[ポリモーフィズム|多態性]](''polymorphism'')
#*アドホック多態性(''ad hoc polymorphism'')
#**[[多重定義|関数オーバーロード]](''function overloading'')
#**[[多重定義|演算子オーバーロード]](''operator overloading'')
#*パラメータ多態性(''parameter polymorphism'')
#**[[ジェネリックプログラミング|ジェネリック関数]](''generic function'')
#**[[ジェネリックプログラミング]](''generic programming'')
#*[[派生型|サブタイプ多態性]](''subtyping'')
#**[[仮想関数]](''virtual function'')
#**動的ディスパッチ(''dynamic dispatch'')
#**[[ダブルディスパッチ]](''double dispatch'')
#**[[多重ディスパッチ]](''multiple dispatch'')
#[[抽象化 (計算機科学)|抽象化]](''abstraction'')
#[[メッセージ (コンピュータ)|メッセージング]](''messaging'')
#ローカル保持(''local retention, protection, hiding of state-process'')
#[[動的束縛|遅延バインディング]](''late binding'')


クラスはデータとメソッドの構成を定義した型であるので、それを計算対象や代入対象になる値として扱うには[[インスタンス]]に実体化(量化)する必要がある。その用法でのクラスはユーザー定義型と呼ばれる。クラスはインスタンスのひな型であり、インスタンスはクラスを量化したものである。ここでの量化とは、そのクラスに属する変数の値を全て決定してメモリに展開する行為を指す。言語によっては後述の[[仮想関数テーブル]]もセットで展開する。インスタンスは別名としてオブジェクトとも呼ばれる。OOPの主役である'''オブジェクト'''の意味と用法は実は曖昧なのが現状であり言語ごとにも違いがある。
=== カプセル化 ===
任意のデータ(変数、プロパティ)群と、それを参照ないし変更するコード(関数、メソッド)群をひとまとめにしてオブジェクトとし、オブジェクト内のデータ群は外部からはアクセスできず隠蔽され、外部公開されたコードを通してのみアクセス可能にした仕組みがカプセル化と呼ばれる。より詳しい解釈については様々だが、オブジェクト指向におけるカプセル化は、基本的に内部隠蔽に焦点を当てたパラダイムである。開発規模の拡大に伴い解決の難しいバグ原因の大半は、データの予期せぬ変化とデータ間の予期せぬ不整合である事が経験則で知られるようになったので、データを変えたコードの位置特定を容易にする為の手段だった。データ直接参照の禁止は予期せぬデータの読み取りを抑止するだけでなく、いわゆる抽象化の一手段も兼ねていた。データを読み取る際にワンクッションの仲介コードを置く事で実行環境の変化に合わせた柔軟なデータ表現を可能にした。ただしこのワンクッション制度は安全性と引き換えにコード記述量を大きくするので、特定のデータとコードに対しては便宜的に直接アクセスを解禁する仕組みも生まれ、これはアクセス権限と呼ばれた。


=== オブジェクト指向の三大要素 ===
カプセル化を推し進めたものとして'''プロトコル'''(''protocol'')がある。これはオブジェクト内部を全隠蔽し、抽象メソッドをまとめた純粋抽象クラスで表現されるインターフェース・オブジェクトを通してアクセスする仕組みを指した。オブジェクトそのものにワンクッションを置いた制度とも言える。プロトコルはオブジェクトの安全な公開を実現し、共同開発とコンポーネント開発に適したものとされた。プロトコルは後述の多態性にも関連しており、特に動的ディスパッチを表現するメカニズムにもなった。
[[クラスベース]]OOPは[[抽象データ型]]の思想に準拠しており、その実装スタイルを規定した以下の三項目は、日本では三大要素または三大原則などと呼ばれている。非OOP言語の[[モジュール]]に三大要素仕様を加えたものがOOP言語のクラスになる。カプセル化は[[This (プログラミング)|this参照]]の機構とデータ/メソッドの可視性を指定できる機能、継承は自身のスーパークラスを指定できる機能、ポリモーフィズムは[[オーバーライド]]と[[仮想関数テーブル]]を処理できる機能である。


=== 継承 ===
==== カプセル化 ====
互いに関連するデータとメソッドをまとめてクラスとし、必要なデータとメソッドのみを外部公開し、それ以外をクラス内に隠蔽する機能をカプセル化と呼ぶ。外部公開されたデータとメソッドはクラス外からの直接アクセスが可能である。内部隠蔽されたデータとメソッドはクラス外からアクセスされないことが保証されこれは{{仮リンク|情報隠蔽|en|information hiding}}と呼ばれる。同クラス所属のメソッドを通してのデータの閲覧と変更はそのデータの抽象化を意味することになりこれは{{仮リンク|Data Abstraction|en|Abstraction (computer science)|label=データ抽象}}と呼ばれる。この二つがカプセル化の要点である。データ抽象を実装するための仕組みでもある[[This (プログラミング)|this参照]]については後節で述べられる。データ閲覧用メソッドはゲッター、データ変更用メソッドはセッターと呼ばれる。データとメソッドの外部公開範囲を、無制限・任意クラスグループ・派生クラスグループの三段階に分けて定義する機能は[[アクセスコントロール]]と呼ばれる。
継承の元々の趣旨はオブジェクトの体系化である。ここでの体系化とは多様な要素をそれぞれ共通と特有の分節構成にし、共通部分から特有部分を派生させる形で関連付ける枝葉状の展開構図に投影する行為を指した。構造体の定義増加で発生しやすい似たようなデータ群の重複に伴う冗長さとその整合性維持の手間隙を解決する為の手段であった。構造体=オブジェクトを複数の階層に分け、共通のデータ集合を親階層とし、特有のデータ集合を子階層として、子階層に親階層へのリンクを持たせて連結する構造にした。A階層から成る親オブジェクトから派生した子オブジェクトはA+B階層として構成され、これが継承と呼ばれた。コードから参照されたデータがB階層に無い時は、次のA階層に有るか探す仕組みとなり、この連鎖によって傍からは一つのオブジェクトとして存在した。データと同様に共通のメソッド群も親階層にまとめられた。その応用として抽象メソッド(=仮想関数)だけの階層を独立させたインターフェースまたは純粋抽象クラスがあり、これを親階層として継承(実装)するのは'''[[派生型|サブタイピング]]'''(''subtyping'')となった。サブタイピングは後述の多態性のメカニズムの一つでもある。なお、派生クラスで任意の機能を追加できる仕組みはコードの再利用性を高めるとも考えられたが、深い継承はクラス構造の把握を困難にするという欠点が明らかになったのでこれは否定された。継承による再利用性はクラスライブラリの使用範囲内に留まっているのが現状である。


==== 継承 ====
なお、子階層の次のリンク先となる親階層は一本だけでなく複数本持つ事も出来るので、複数の親階層+子階層によるオブジェクト構成は'''多重継承'''と呼ばれた。子階層が持つ親階層アドレスは一般にリスト化されており、自身に無いデータはリスト先頭の親階層から順々に検索された。その親階層が多重継承されてる場合も同様であり、それぞれの枝分かれには深さ優先検索が用いられた。前述のサブタイピングは多重で行われる事が多い。
既存クラスのデータ/メソッド構成に任意のデータ/メソッド構成を付け足して、既存構成+新規構成の新しいクラスを定義する機能を継承と呼ぶ。その差分プログラミング目的の継承よりも、既存構成に抽象メソッドを置いて新規構成にその実体メソッドを置くというオーバーライド目的の継承の方が要点にされている。新規構成ではなく実装内容を付け足していくための継承である。既存クラスは基底クラス、親クラス、スーパークラスなどと呼ばれ、新しいクラスは派生クラス、子クラス、サブクラスなどと呼ばれる。抽象メソッドを持つクラスは抽象クラスと呼ばれる。継承できるクラスが一つに限られている単一継承を採用している言語と、継承できるクラスの数に制限がない多重継承を採用している言語に分かれている。抽象メソッドのみで構成される純粋抽象クラスの継承は、インターフェースの{{仮リンク|実装継承|en|Inheritance_(object-oriented_programming)}}と呼ばれて抽象化目的の継承になる。


=== 多態性 ===
==== ポリモーフィズム ====
異なる種類のクラスに同一の操作インターフェースを持たせる機能をポリモーフィズム(多態性)と呼ぶ。これはクラスの継承関係を利用して、コンパイル時のメソッド名から呼び出されるプロセス内容を実行時に決定するという仕組みを指す。その実装は{{仮リンク|仮想関数(OOP)|en|Virtual function|label=仮想関数}}と呼ばれており、クラスベースOOPのポリモーフィズムはイコール仮想関数となっている。仮想関数はスーパークラスの抽象メソッドの呼び出しを、それを[[オーバーライド]]したサブクラスの実体メソッドの呼び出しにつなげる機能である。抽象メソッドとオーバーライド機能については後節で述べる。ポリモーフィスムの要点は、同じメソッド名からその実行時に対応した異なる処理内容を呼び出せるようにすることである。
アドホック多態性は単にソースコードの記述を一部自動化するものである。'''関数オーバーロード'''は引数の並び方パターンによって同じ名前のメソッドをコンパイル時に自動的に差別化する機能である。'''演算子オーバーロード'''は、扱う数値の型に従って宣言された演算記号を関数名と見なすようにし、単項演算子なら右の数値を第一引数とし、二項演算子なら左右の数値をそれぞれ第一第二引数として関数呼び出しのコードが生成されるという仕組みだった。丸括弧の演算子は関数オブジェクトの表現として使用出来た。これらは静的な多態性とされる。


=== コンポジションとデリゲーション ===
パラメータ多態性もソースコードの記述を一部自動化するものである。関数&クラスのコード内の特定の型部分をワイルドカードにして記述しておき、ソースコード内で具体的な型の指定と共に関数&クラスの呼び出しが記述されると、その型を先のワイルドカードに当てはめた関数&クラスのコードがコンパイル時に自動生成されるという機能だった。&の前者は'''ジェネリック関数'''と呼ばれ、後者はより広い範囲を扱う事から'''ジェネリックプログラミング'''と名付けられた。これらも静的な多態性に位置付けられている。
コンポジション(合成)とデリゲーション(委譲)は、継承の原型的仕組みであり、別の言い方をすると合成+委譲を最適化した機能が継承である。継承は[[is-a]]構造の委譲、合成は[[has-a]]構造の委譲と読み替える事ができる。合成とは、クラスに特定処理の委譲先となる部品クラスを複数持たせた構造であり、合成クラスがデータ/メソッドを要求されて自身が未所持の場合は、対応可能な部品クラスを選択して委譲するという仕組みである。その要求判別と選択過程を自動化したのが継承であり、部品クラスを親クラスに置き換えて暗黙の委譲先にしたものである。しかしその暗黙委譲は実際に参照されるデータ/メソッドの把握を困難にするという欠点も明らかになったので、合成の価値が再認識されるようになった。既存構成に新規構成を付け足していく差分プログラミング目的では、継承よりも合成を用いる方がよいと考えられている。


=== 動的ディスパッチとメッセージパッシング ===
サブタイプ多態性は動的なものである。最も初期のOOPであるSimula67は、シミュレーション内で扱う多種多様なオブジェクトを継承によって体系化したが、コード部分の細かな違いは共通スーパークラスに属する共通プロシージャ内の分岐フローで処理していた。サブクラスの数だけ分岐構文が増える頻雑さを解消するために、共通プロシージャをただの[[仮想関数テーブル]]にしてサブクラスの実装時に同名プロシージャのアドレスを収納させ、共通プロシージャ呼び出し時にそのアドレスへジャンプするという機能が考案された。[[仮想関数テーブル]]はプロシージャの仮想的存在と見なされたので、この機能は'''仮想関数'''と呼ばれた。'''動的ディスパッチ'''はSmalltalkのオブジェクト設計に由来するものであり、その実装の仕方は様々でやや曖昧な仕様でもある。メッセージを受け取ったレシーバーがオブジェクト内部で動的な状態に従い動的な処理を行って結果を返すというランタイム環境上のプロセスが後に動的ディスパッチのカテゴリで括られた。[[分散コンピューティング]]を表現する[[Object Request Broker|オブジェクト間通信]]とそれに基づく[[ソフトウェアコンポーネント]]も動的ディスパッチに該当するものである。'''多重ディスパッチ'''は動的な関数オーバーロードに近いものである。関数コール時または関数ブロック内で、それぞれの引数が動的に型審査されて型変化(''dynamic casting'')された後に、その引数パターンに対応した同名関数または分岐ルーチンに処理が移行されるという動的変化プロセスを指した。'''ダブルディスパッチ'''は多重ディスパッチの亜流的存在であり、二通りの考え方がある。動的型審査および型変化されるBオブジェクトを単一引数にしてAオブジェクトの仮想関数メソッドを呼び出す形態と、多重ディスパッチに用いる引数を二つに限定した形態である。いずれも実行時状態に応じた動的変化プロセスとなった。これは主にデータ集合を対象にして分類、解析、作用といった処理を連続的または再帰的に行うアルゴリズムで用いられた。
動的ディスパッチはポリモーフィズムの原型的仕組みであり、継承構造上での[[This (プログラミング)|this]]参照によるシングルディスパッチを最適化した機能が仮想関数である。動的ディスパッチはコンパイル時のメソッド名から呼び出されるメソッド内容が実行時に決定される仕組み全般を指す用語であり、メソッド名を基軸にして各引数の型によってプロセスが選択分岐される仕組みを意味するシングルディスパッチと[[多重ディスパッチ]]を包括している。一つの引数の型がプロセス選択に影響するのはシングル、二つ以上なら多重になる。


メッセージパッシングでは、引数の型に加えてメソッド名も実行時に解釈される要素にされておりそれはセレクタと呼ばれる。<code>object selector: param</code>ような書式でオブジェクトの共通窓口となるメッセージレシーバーにセレクタと引数のメッセージが送られる。また、<code>object.call(method_name, param)</code>のような書式でオブジェクトの共通窓口関数をコールするのもメッセージパッシングと呼ばれる。これは[[Remote Procedure Call|遠隔手続きコール]]や[[Object Request Broker|オブジェクト要求ブローカー]]で用いられており分散オブジェクトの標準的なインターフェース機構になっている。関数名も実行時に解釈されるという特徴を指してメッセージパッシングと呼ぶ。よく用いられるセレクタ対応プロセスを自動選択化してコンパイル時最適化した仕組みがメソッドになり、これは関数名をコンパイル時決定する関数呼び出しと同類になった。
=== 抽象化 ===
純粋抽象クラスの仕組みがこれに相当する。実例としては[[ソフトウェアコンポーネント]]及び[[Java]]などのプログラミング言語で用いられている[[インタフェース (抽象型)|インターフェース]]がある。この抽象化は、カプセル化の{{仮リンク|.プロトコル|en|Protocol (object-oriented programming)|label=}}、継承の[[派生型|サブタイピング]]、多態性の仮想関数をまとめたパラダイムと考える事が出来る。


=== インターフェース ===
[[C++]]開発者の[[ビャーネ・ストロヴストルップ]]は、広義のオブジェクト指向の主要サポート案件として抽象化、継承、実行時多態性(''run-time polymorphism'')の三点を挙げていた。抽象化は同時に完全な内部隠蔽になるので、コンクリートクラスの中途半端な内部隠蔽ではなく、純粋抽象クラスのプロトコルを重視していた事が分かる。
インターフェースはカプセル化を更に突き詰めた仕組みであり、データ抽象とメソッド抽象と情報隠蔽を合わせて実現する最もOOPらしい機能と言える。インターフェースは抽象メソッドのみで構成されている純粋抽象クラスである。ゲッター、セッター、プロセスになる各抽象メソッドの実装内容は利用者側から隠されて実行時のその都度に決定される。


=== メッセーング ===
=== プロトタイプとオブェクト ===
[[クラスベース]]のクラスと実体化とインスタンスは、[[プロトタイプベース]]ではプロトタイプと複製とオブジェクトに置き換わる。プロトタイプとオブジェクトの大きな特徴は、プロパティとメソッドを自由に付け替えできることでありこれは[[動的束縛|動的バインディング]]とも呼ばれ、そのプロパティとメソッドの構成による型は[[ダックタイピング]]で判別される。この特徴は同時に[[ポリモーフィズム]]になる。その用法は[[関数オブジェクト]]と変数オブジェクト(値オブジェクト)に大別され、前者は[[二階述語論理]]、後者は[[高階述語論理]]の表現体になり、それ自体が[[メタデータ|メタ]]視点から抽象化されたオブジェクトには[[カプセル化]]という概念は必要でなくなる。[[継承 (プログラミング)|継承]]の意味合いも異なりクラスベースの基底と派生は、プロトタイプベースではプロパティ/メソッド構成のアタッチ候補とそのアタッチ先に置き換わる。アタッチ候補は親クラスや[[トレイト]]などと呼ばれる。アタッチ候補は事実上の[[委譲|デリゲーション]]先でもある。トレイトは多重継承前提でありこれは[[ミックスイン]]と呼ばれ、構造的型付けでその実装継承が判別される。
メッセージングは哲学的側面が強いパラダイムである。仕組み的には、オブジェクト(=インスタンス)のメソッドコール、または[[Object Request Broker|オブジェクト間通信]]におけるリモートメソッドコールと同じものと考えてよいが、メッセージングのパラダイム下では、イメージ的にオブジェクトそのものをメソッドとしてコールする点が異なっている。それは各オブジェクトが一般にレシーバーと呼ばれるデフォルトメソッドを持つ事で実現されている。オブジェクトのコールとは、このレシーバーをコールするのと同義となる。引数無しでコールされる事はなく、基本的に一つのオブジェクトが引数となってコールされる。これも留意すべき点である。元祖オブジェクト指向では「''EverythingIsAnObject''」の通り、[[プリミティブ型|プリミティブ]]から[[構造体|データストラクチャ]]、[[コードブロック]]まであらゆるプログラム要素がオブジェクトとされる。ここにオブジェクトA、Bがあるとすると、メッセージングの基本構文は「A B」のようになる。これは「Bを引数にしてAを呼び出す」の意味であり、イメージ的に「Aに対してBというメッセージを送る」と形容される。引数Bを受け取ったAのレシーバー内で任意の処理が行われた後に結果値としてのオブジェクトが返される。Aそのものが返される事もあれば、別のオブジェクトが返される事もある。この流れがメッセージングと呼ばれるものである。返値オブジェクトに対して別のメッセージを送る事も可能であり、また返値オブジェクトをメッセージにして別のオブジェクトに送る事も出来る。こうしたメッセージングの連鎖はAのレシーバー内でも同様に行なわれる。メッセージング・パラダイム下でのオブジェクトは言わば独自の記憶を備えた変換式であり、これらオブジェクトのコミュニケーションとは[[高階関数]]と[[第一級関数]]の仕組みと同じものである。メッセージング・パラダイムの本質はオブジェクトの代数(''algebra'')化であり、その代数値は前述のメッセージングの連鎖による結果値である。メッセージングを行なうオブジェクトもまたメッセージング連鎖の集合体という事になる。それはただの[[プリミティブ|プリミティブ値]]であっても決して例外ではない。レシーバーでの処理をコードとすると、メッセージング・パラダイム下でのデータはメッセージング連鎖によるコードの集合体であり、その各コードは他のデータ群を参照しており、その各データもまたコードの集合体~という風になる。勿論最終的には根っことなるオブジェクトの定形データに行き着いてそれが値算出の原点になるが、こうなるとイメージ的にコードとデータが融合して両者の区別はなくなる。オブジェクトは抽象化の一形態である代数的(''algebraic'')存在なので、代数計算と同様に理念的には単体で成り立つ事はなく、二つのオブジェクトが出会うメッセージングによって始めて一定のプロセスが発生し、または一つのデータが体現される。これが引数無しでもよいメソッドと引数が要るメッセージングの明確な違いである。

なお、実装面では便宜上の理由から、メッセージングの際の引数オブジェクトにはセレクタを付けるのが許容されている。大抵は「A ''selector'':B」の様になる。セレクタはメソッド名と同義であり、引数オブジェクトに貼られるラベルと考えていいものである。セレクタによってレシーバー外の対応メソッドに自動分岐されるのでコーディングが簡便になる。[[演算子]]も事実上のセレクタであり「5+3」は、+セレクタを貼った3オブジェクトを5に送ると解釈できる。括弧記号はコンパイラのためのただの[[ディレクティブ]]となる。メッセージングは二つのオブジェクトが出会った時点で発生するプロセスなので引数は常に一つであり、複数の引数を用いたい場合はパーシャルアプリケーションまたは[[カリー化]]を適用するべきであるが、これは困難なコーディングになる事が多いので、セレクタによる[[パターンマッチング]]的な各メソッドへの自動分岐も許容されている。

このメッセージングのパラダイムは様々な理由から広くは認知されず、やがてその言葉だけが一人歩きするようになって本来の定義からシフトし、前述のレシーバーの仕組み自体がメッセージングと見なされるようにもなり、[[Object Request Broker|オブジェクト間通信]]で行なわれるバイトデータ列の送受信もメッセージングの代表例とされるようになった。また、インスタンスの単純なメソッド呼び出しもメッセージングであると説明される事もある。この様にメッセージングの本質は見失われながらも、その側面的仕様は数々のOOP言語に導入されてもいる。

=== ローカル保持 ===
{{節スタブ}}

=== 遅延バインディング ===
{{節スタブ}}


[[プロトタイプベース]]は動的な[[関数型プログラミング]]に似た性質になっているが、オブジェクトの柔軟な用法に対しての一定の枠組みが必要であるとも考えられるようになり、静的な[[クラス (コンピュータ)|クラス]]定義が積極的に導入されるようになった。現状のプロトタイプベースは元来の[[The Art of the Metaobject Protocol|メタオブジェクト]]構想から離れて、関数型とOOPのハイブリッドのようなパラダイムに落ち着いている。


=== アラン・ケイのメッセージング ===
メッセージングはオブジェクト指向の父である[[アラン・ケイ]]が最重視していた源流思想である。ここでは各自が解釈できるように彼の言葉をそのまま引用して本節の結びとする。{{Quotation|''I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages.''<br>(さながら生物の細胞、もしくはネットワーク上の銘々のコンピュータ、それらはただメッセージによって繋がり合う存在、僕はオブジェクトをそう考えている)|Alan Kay}}{{Quotation|''... each object could have several algebras associated with it, and there could be families of these, and that these would be very very useful.''<br>(銘々のオブジェクトは関連付けられた幾つかの「代数」を持つ、またそれらの系統群も持つかもしれない、それらは極めて有用になるだろう)|Alan Kay}}{{Quotation|''The Japanese have a small word - ma ... The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.''<br>(日本語には「間」という言葉がある・・・成長的なシステムを作る鍵とは内部の特徴と動作がどうあるべきかよりも、それらがどう繋がり合うかをデザインする事なんだ)|Alan Kay}}
== 歴史 ==
== 歴史 ==
1954年に初の[[高水準言語]]・[[FORTRAN]]が登場すると、開発効率の劇的な向上と共にソフトウェア要求度も自然と高まりを見せてプログラム規模の急速な拡大が始まった。それに対応するために肥大化したメインルーチンを[[サブルーチン]]に分割する手法と、[[スパゲティプログラム|スパゲティ化]]した[[Goto文|goto命令]]を[[制御構造|制御構造文]]に置き換える手法が編み出され、これらは1960年に公開された言語「[[ALGOL|ALGOL60]]」で形式化された。当時のALGOLは[[アルゴリズム]]記述の一つの模範形と見なされたが、それと並行して北欧を中心にした計算機科学者たちはより大局的な観点によるプログラム開発技法の研究を進めていた。
オブジェクト指向プログラミングという考え方が生まれた背景には、計算機の性能向上によって従来より大規模な[[ソフトウェア]]が書かれるようになってきたということが挙げられる。大規模なソフトウェアが書かれコードも複雑化してゆくにつれ、ソフトウェア開発コストが上昇し、[[1960年代]]には「[[ソフトウェア危機]] ({{Lang|en|software crisis}})」といったようなことも危惧されるようになってきた。そこでソフトウェアの[[再利用 (プログラミング)|再利用]]、[[部品化 (プログラミング)|部品化]]といったようなことを意識した仕組みの開発や、[[ソフトウェア開発工程]]の体系化('''[[ソフトウェア工学]]''' ({{Lang|en|software engineering}}) の誕生)などが行われるようになった。


=== Simulaの開発(1962 - 72) ===
このような流れの中で、プログラムを構成するコードとデータのうち、コードについては[[プロシージャ|手続き]]や[[関数 (プログラミング)|関数]]といった仕組みを基礎に整理され、その構成単位を[[ブラックボックス]]とすることで再利用性を向上し、部品化を推進する仕組みが提唱され'''[[構造化プログラミング]]''' ({{Lang|en|structured programming}}) として{{要出典範囲|date=2019年2月|[[1967年]]}}に[[エドガー・ダイクストラ]] ({{Lang|en|Edsger Wybe Dijkstra}}) らによってまとめあげられた(プログラミング言語の例としては[[Pascal]] [[1971年]])。なお、それに続けて「しかしデータについては相変わらず主記憶上の記憶場所に置かれている限られた種類の[[基本データ型]]の値という比較的低レベルの抽象化から抜け出せなかった。これはコードはそれ自身で意味的なまとまりを持つがデータはそれを処理するコードと組み合わせないと十分に意味が表現できないという性質があるためであった。」といったように、ほぼ間違いなく説明されている。
1962年、ノルウェー計算センターで[[モンテカルロ法]]シミュレーションを運用していた計算機科学者[[クリステン・ニゴール]]は、[[ALGOL|ALGOL60]]を土台にしてProcessと呼ばれる[[コルーチン]]機構を加えたプログラミング言語「[[Simula]]」を公開し、続けてその拡張にも取り組んだ。ニゴールの同僚で、1963年にSimulaを[[メインフレーム|汎用機]][[UNIVAC I|UNIVAC]]系統上で運用できるように実装した計算機科学者[[オルヨハン・ダール]]は、Processにローカル変数構造を共有する手続き(サブルーチン)を加えてパッケージ化する言語仕様を考案し、これは一定の変数と手続きをまとめる[[モジュール]]と同類の機能になった。程なくしてALGOL60コンパイラに準拠していての限界を悟ったニゴールとダールは、1965年からSimulaを一から再設計するように方針転換した。その過程で彼らは、計算機科学者[[アントニー・ホーア]]が考案して1962年のSIMSCRIPT([[FORTRAN]]用のスクリプト)に実装していたRecord Classを参考にしている。Record Classはソースコード水準の抽象表現を、各[[メインフレーム|汎用機]]に準拠した[[マシンコード]]水準の実装符号に落とし込む段階的データ構造のプログラム概念であった。これをモデルにした[[継承 (プログラミング)|継承]]と、その継承構造を利用した仮想手続き(仮想関数)の仕組みも考案され、上述のパッケージ化されたProcess(モジュール)に継承と仮想手続きの両機能を加えたものを「[[クラス (コンピュータ)|クラス]]」と定義し、クラスをメモリに展開したものを「[[オブジェクト (プログラミング)|オブジェクト]]」と定義する言語仕様がまとまり、1967年に「[[Simula|Simula67]]」が初公開された。オブジェクトという用語は、[[MIT]]の計算機科学者[[アイバン・サザランド]]が1963年に開発した[[Sketchpad]]([[CAD]]と[[GUI]]の元祖)の設計内にあるObjectが先例であった。Simula67コンパイラはまず[[UNIVAC I|UNIVAC]]上で運用され、翌年から汎用機[[バロース B5000|バロースB5500]]などでも稼働されて北欧、ドイツ、ソ連の各研究機関へと広まり、1972年には[[IBMメインフレーム|IBM汎用機]][[System/360]]などにも導入されて北米全土にも広まった。その主な用途は物理シミュレーションであった。{{Quotation|''influenced by Sketchpad, Simula, the design for the ARPAnet, the Burroughs B5000, and my background in Biology and Mathematics, I thought of an architecture for programming.''
<br>([[Sketchpad]]、[[Simula]]、[[アーパネット|ARPAネット]]、[[バロース B5000|バロースB5000]]、それと専攻していた生物学と数学に影響されて僕はプログラミングアーキテクチャを思索していた)|Alan Kay}}
=== 構造化プログラミングの提唱(1969 - 75) ===
[[Simula]]の普及と前後して1960年代半ばになると、プログラム規模の際限ない肥大化に伴う開発現場の負担増大が顕著になり、いわゆる[[ソフトウェア危機]]問題が計算機科学分野全般で取り沙汰されるようになった。その解決に取り組んだ計算機科学者[[エドガー・ダイクストラ]]は、1969年のNATOソフトウェア工学会議で「[[構造化プログラミング]]」という論文を発表し[[トップダウン設計とボトムアップ設計|トップダウン設計]]、段階的な[[抽象化 (計算機科学)|抽象化]]、階層的な[[モジュール化]]、共同詳細化(抽象データ構造と抽象ステートメントのjoint)といった構造化手法を提唱した。ダイクストラの言う構造化とは開発効率を高めるための[[分割統治法]]を意味していた。なおこの構造化プログラミングは後に曲解されて[[制御構造|制御構造文]]を中心にした解釈の方で世間に広まり定着している。共同詳細化は抽象データ構造を専用ステートメントを通して扱うという概念である。これはSimulaの手続きを通してクラス内の変数にアクセスするという仕組みをモチーフにしていた。段階的な抽象化と階層的なモジュール化は時系列的にも、SIMSCRIPTの段階的データ構造と、Simura67の継承による階層的クラス構造を模倣したものであった。[[エドガー・ダイクストラ|ダイクストラ]]、[[アントニー・ホーア|ホーア]]、[[オルヨハン・ダール|ダール]]の三名は1972年に『構造化プログラミング』と題した共著を上梓していることから互いの研鑽関係が証明されている。その階層的プログラム構造という章の中でダールは、Simulaの目指した設計を更に明らかにした。{{Quotation|''I'm not against types, but I don't know of any type systems that aren't a complete pain, so I still like dynamic typing.''
<br>(僕は型アンチではないが、全くうんざりしない型システムも知らない、だからまだ動的型付けを好んでいる)|Alan Kay}}1974年に[[MIT]]の計算機科学者[[バーバラ・リスコフ]]は「[[抽象データ型]]」というプログラム概念を提唱し、ダイクストラが提示したモジュールの共同詳細化を、その振る舞いによって[[セマンティクス|意味内容]]が定義される抽象データという考え方でより明解に形式化した。一方、1970年に構造化言語[[Pascal]]を開発していた計算機科学者[[ニクラウス・ヴィルト]]は、ダイクストラによる共著出版後の1975年にモジュール化言語[[Modula-2|Modula]]を提示してモジューラプログラミングというパラダイムを生み出している。このようにいささか奇妙ではあるが、Simulaのクラスとオブジェクトというプログラム概念は、巷で言われる構造化からモジュール化へといった進化の流れとは関係なく、しかもその前段階においてさながら彗星のように生まれたパラダイムであった。


=== Smalltalkとオブジェクト指向の誕生(1972 - 81) ===
そこでデータを構造化し、ブラックボックス化するために考え出されたのが、データ形式の定義とそれを処理する手続きや関数をまとめて一個の構成単位とするという考え方で'''[[モジュール]]''' ({{Lang|en|module}}) と呼ばれる概念である([[プログラミング言語]]の例としては[[Modula-2]] 1979年)。しかし定義とプログラム内の実体が一対一に対応する手続きや関数とは異なり、データはその形式の定義に対して値となる実体([[インスタンス]]と呼ばれる)が複数存在し、各々様々な寿命を持つのが通例であるため、そのような複数の実体をうまく管理する枠組みも必要であることがわかってきた。そこで単なるモジュールではなく、それらのインスタンスを整理して管理する仕組み(例えば[[クラス (コンピュータ)|クラス]]とその[[継承 (プログラミング)|継承]]など)まで考慮して生まれたのが[[オブジェクト (プログラミング)|オブジェクト]]という概念である(プログラミング言語の例としては1967年の[[Simula|Simula 67]]<!--言語機能としての「クラス」はSimula 67から-->)。
Simula発のProcessとクラスの仕様は、[[パロアルト研究所]]の計算機科学者[[アラン・ケイ]]によるオブジェクト重視と「メッセージング」という考え方のヒントになった。ケイはプログラム内のあらゆる要素をオブジェクトとして扱い、オブジェクトはメッセージの送受信でコミュニケーションするという独特のプログラム理論を提唱した。それには関数適用風の書式を用いたオブジェクト同士の多種多様な[[委譲|デリゲーション]]と、プログラムコードとしても解釈できるデータ列を送信してそれを評価(''eval'')することで新たなデータを導出できるなどのアイディアが盛り込まれていた。オブジェクトが送るか受け取ったメッセージは任意のタイミングで評価できるので非同期通信や単方向通信をも可能にしていた。この発想の背景には[[LISP]]の影響があった。オブジェクトとメッセージングの構想に基づいて開発された「[[Smalltalk]]」はプログラミング言語と[[GUI]]運用環境を併せたものとなり、1972年に[[Alto|ゼロックスAlto]]上で初稼働された。Smalltalkの設計を説明するためにケイが考案した「[[オブジェクト指向]]」という用語はここで初めて発信された。またケイのメッセージング構想は[[MIT]]の計算機科学者[[カール・ヒューイット]]に能動的な[[プロセス代数]]を意識させて、1973年発表の[[アクターモデル]]のヒントにもなっている。しかしデリゲーションの多用とデータ列が常にコード候補として扱われる処理系は、当時のコンピュータには負荷が大きく実用的な速度を得られないという問題にすぐ直面した。Smalltalk-74とSmalltalk-76の過程で、やむなくメッセージは構想時の柔軟さが失われるほどシステム向けに最適化され、レシーバーはセレクタパターン重視のメソッド化が進み、オブジェクトは静的なクラス定義の存在感が大きくなった。{{Quotation|''Smalltalk is not only NOT its syntax or the class library, it is not even about classes. I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea.The big idea is "messaging"...''
<br>(Smalltalkはその構文やライブラリやクラスをも関心にしていないという事だけではない。多くの人の関心を小さなアイディアに向かせたことから、僕はオブジェクトという用語を昔作り出したことを残念に思っている。大切なのはメッセージングなんだ。)|Alan Kay}}1980年のSmalltalk-80は、元々はメッセージを重視していたケイを自嘲させるほど同期的で双方向的で手続き的なオブジェクト指向へと変貌していた。それでも動的ディスパッチと[[委譲]]でオブジェクトを連携させるスタイルは画期的であり、1994年に発表される[[デザインパターン (ソフトウェア)|デザインパターン]]の模範にもされている。1981年に当時の著名なマイコン専門誌『[[Byte (magazine)|BYTE]]』がSmalltalkとケイ提唱のオブジェクト指向を紹介して世間の注目を集める契機になったが、ケイの思惑に反して技術的関心を集めたのはクラス機構の方であった。オブジェクト指向は知名度を得るのと同時に、Simula発の[[クラス (コンピュータ)|クラス]]とそれを理論面から形式化した[[抽象データ型]]を中心に解釈されるようになり、それらの考案者がケイの構想とは無関係であったことから、オブジェクト指向の定義はケイの手を離れて独り歩きするようになった。


=== C++の開発と普及(1979 - 88) ===
Simulaのオブジェクトとクラスというアイデアは異なる二つの概念に継承される。一つはシステム全てをオブジェクトの集合と捉え、オブジェクトの相互作用を'''メッセージ'''に喩えた「[[オブジェクト指向]]」である。オブジェクト間の相互作用をメッセージの送受と捉えることで、オブジェクトは受信したメッセージに見合った手続き単位(≒関数)を自身で起動すると考える。結果オブジェクトは自身の持つ手続きのカプセル化を行うことができ、メッセージが同じでもレシーバオブジェクトによって行われる手続きは異なる――[[ポリモーフィズム|多相性]](ポリモーフィズム)を実現した(このメッセージを受け実行される手続き単位は、メッセージで依頼されたことを行うための「手法」の意味で[[メソッド (計算機科学)|メソッド]]と呼ばれる)。この思想に基づき作られたのが[[Smalltalk]]([[1972年]])であり、[[オブジェクト指向]]という言葉はこのとき[[アラン・ケイ]]によって作られた。
[[Simula]]を研究対象にしていた[[ベル研究所|AT&Tベル研究所]]の計算機科学者[[ビャーネ・ストロヴストルップ]]は、1979年からクラス付きC言語の開発に取り組み、1983年に「[[C++]]」を公開した。C++で実装された[[クラス (コンピュータ)|クラス]]は、Simula譲りの[[継承 (プログラミング)|継承]]と仮想関数に加えて、[[レキシカルスコープ]]の概念をクラス構造に応用した[[アクセスコントロール]]を備えていた。C++で確立されたアクセスコントロールはカプセル化の元になったがコードスタイル上ほとんどザル化されており、その理由からストロヴストルップ自身もC++は正しくない(''not just'')オブジェクト指向言語であると明言している。1986年にソフトウェア技術者[[バートランド・メイヤー]]が開発した「[[Eiffel]]」の方は、正しいオブジェクト指向を標榜してクラスのデータ抽象を遵守させるコードスタイルが導入されていた。クラスメンバ(フィーチャー)は属性、手続き、関数の三種構成で、手続きで属性を変更し関数で属性を参照するという形式に限定されており、これは抽象データ型の[[セマンティクス|振る舞い意味論]]に沿った実装であった。アクセスコントロールはモジューラプログラミングの情報隠蔽に沿った方式になり、仮想関数機能は延期手続き/関数として実装された。{{Quotation|''I made up the term ‘object-oriented’, and I can tell you I didn’t have C++ in mind.''
<br />(僕はオブジェクト指向という言葉を作ったけど、C++(のような言語)は考えていなかった)|Alan Kay}}1986年から[[Association for Computing Machinery|ACM]]が[[OOPSLA|オブジェクト指向会議]](OOPSLA)を年度開催し、そのプログラミング言語セクションでは[[抽象データ型]]の流れを汲む[[クラス (コンピュータ)|クラス]]・パラダイムが主要テーマにされ、それを標準化するための数々のトピックが議題に上げられている。[[モジュール性]]、情報隠蔽、[[抽象化 (計算機科学)|抽象化]]、再利用性、[[継承 (プログラミング)|階層構造]]、複合構成、実行時多態、[[動的束縛]]、[[総称型]]、[[ガベージコレクション|自動メモリ管理]]といったものがそうであり、参画した識者たちによる寄稿、出版、講演を通して世間にも広められた。そうした潮流の中で[[ビャーネ・ストロヴストルップ|ストロヴストルップ]]はデータ抽象の重要性を訴え、[[バーバラ・リスコフ|リスコフ]]は[[上位概念、下位概念、同位概念および同一概念|基底と派生]]に分けたデータ抽象の[[リスコフの置換原則|階層構造の連結関係]]について提言した。[[契約による設計]]を提唱する[[バートランド・メイヤー|メイヤー]]が1988年に刊行した『オブジェクト指向ソフトウェア構築』は名著とされ、Eiffelを現行の模範形とする声も多く上がった。ただしこれは学術寄りの意見でもあったようで、世間のプログラマの間では厳格なEiffelよりも柔軟で融通の利くC++の人気の方が高まっていた。他方でオブジェクト指向本来の原点であるメッセージ・メタファに忠実であろうとする動きもあり、1984年に開発された「[[Objective-C]]」はSmalltalkをモデルにしてそれを平易化した言語であった。そのメッセージレシーバーは静的なメソッド機構優先の動的ディスパッチ機構という方式で実装された。メッセージレシーバの仕組みは[[遠隔手続き呼出し]]/[[Object Request Broker|オブジェクト要求ブローカー]]の実装に適していたので[[分散システム]]とオブジェクト指向の親和性を認識させることになった。


=== プロトタイプベースの黎明(1979 - 91) ===
一方、Smalltalkとは別にSimulaの影響を受け作られた[[C++]]([[1979年]])は[[抽象データ型]]のスーパーセットとしてのクラス、オブジェクトに注目し、オブジェクト指向をカプセル化、継承、多相性をサポートするものと再定義した(その際、実行時速度重視およびコンパイラ設計上の制約により、変数メタファである[[動的束縛]]の特徴は除外された)。これらは当初[[抽象データ型]]、[[派生]]、[[メソッド (計算機科学)#仮想関数|仮想関数]]と呼ばれ、オブジェクトのメンバ関数を実体ではなくポインタとすることで、継承関係にあるクラスのメンバ関数の[[オーバーライド]](上書き)を可能にしたことで、多相性を実現した(この流儀では'''メッセージメタファ'''はオブジェクト指向に必須ではないものと定義し、オブジェクトの持つ手続きをメソッドとは呼ばず[[メソッド (計算機科学)|メンバ関数]]と呼ぶ)。この他、Smalltalkにある[[動的束縛]]の類似的な機能としてオーバーロード([[多重定義]])が実装されている。
[[アラン・ケイ]]がその影響を言及していた[[LISP]]コミュニティでは1970年代後半から、[[Smalltalk]]が提唱するオブジェクト指向と[[LISP]]プログラミングの融合が研究されており、LISPのオブジェクト指向拡張版と称されたFlavorsが[[MIT人工知能研究所]]の[[LISPマシン]]上で実装されるようになった。Flavorsのオブジェクト指向デザインはLISPの[[関数型言語|関数型]]思想で再解釈されつつ[[Common Lisp]]に融合され、1988年に「[[Common Lisp Object System]] (CLOS)」が発表された。CLOSは[[メタクラス]]、[[動的型付け]]と[[多重ディスパッチ]]の合わせ技であるジェネリック関数、構造的型付けと[[多重継承]]の合わせ技である[[ミックスイン]]、メソッドコンビネーションといった特徴的な機能を備えており、そのLISP風の[[動的型付け]]は後年に定義される[[ダックタイピング]]のルーツになり、メソッドコンビネーションの方は[[アスペクト指向プログラミング|アスペクト指向]]のルーツになった。CLOSの設計思想は「[[The Art of the Metaobject Protocol|メタオブジェクトプロトコル]]」の名でまとめられて1991年に[[パロアルト研究所]]フェローから著述発表されており、こちらは[[Smalltalk]]のEverythingIsAnObject思想をより具体化した[[プロトタイプベース]]のルーツになっている。また、同研究所でSmalltalkの方言として制作されていた「[[Self]]」が1987年に初回稼働され1990年に一般公開された。Selfにも導入されていたメタオブジェクト相当の仕様が、後に[[プロトタイプベース]]と呼ばれるオブジェクト指向スタイルに発展した。{{Quotation|The Art of the Metaobject Protocol ―<br />
''some of the most profound insights, and the most practical insights about OOP''<br />(オブジェクト指向への最も深遠な洞察と、最も実用的な見識の数々)|Alan Kay}}


=== コンポーネントとネットワーク(1989 - 97) ===
Smalltalkはこの「全てをオブジェクトとその相互作用で表現する」というデザインに立ち設計されたため、全てをファイルと捉える'''ファイル指向[[オペレーティングシステム]]'''からの脱却と、プログラムをフロー制御された手続きと捉える'''手続き型言語'''からの脱却が行われた。そのためSmalltalkは自身が'''オブジェクト指向オペレーティングシステム'''でもあること、メッセージ・パッシングなどの特徴を持った。これは当時のプログラム言語としては特異的であり、[[ガベージコレクション|ガベージコレクタ]]を必要とし、高度な最適化が試される前のバイトコード[[インタプリタ]]で実行される処理の重さも手伝って先進的ではありながら普及しがたいものであると捉えられた。また、メッセージでの多相性は、変数へのオブジェクトの[[動的束縛]]が前提となるため、静的型チェック機構でのサポートが難しく、C++等の実行時性能重視の言語にとって実装から除外すべき特徴となった。
ネットワーク技術の発展に連れて、データとメソッドの複合体であるオブジェクトの概念は、[[分散システム]]構築のための基礎要素としての適性を特に見出される事になり、[[IBM|IBM社]]、[[アップル (企業)|アップル社]]、[[サン・マイクロシステムズ|サン社]]などが1989年に共同設立した[[Object Management Group|OMG]]は、企業システムネットワーク向け分散オブジェクトプログラミングの標準規格となる[[CORBA]]を1991年に公開した。その前年に[[マイクロソフト|マイクロソフト社]]は[[ウェブアプリケーション]]向けの分散オブジェクト技術となる[[OLE]]を発表し、1993年には[[Component Object Model|COM]]と称する[[ソフトウェアコンポーネント]]仕様へと整備した。この[[Component Object Model|COM]]の利用を眼目にしてリリースされた「[[Microsoft Visual C++|Visual C++]]」「[[Visual Basic]]」は[[World Wide Web|ウェブ]]時代の新しいプログラミング様式を普及させる先駆になった。この頃に[[抽象データ型]]のメソッドを通したデータ抽象、データ隠蔽、[[アクセスコントロール]]および分散オブジェクト=[[プロセス間通信]]の[[インタフェース (情報技術)|インターフェース]]機構によるプログラムの抽象化といった概念は、[[カプセル化]]という用語にまとめられるようになった。クラスの[[継承 (プログラミング)|継承]]が最もオブジェクト指向らしい機能と見なされていたのが当時の特徴であった。継承構造を利用したサプタイピングは[[多態性]]という用語に包括され、多重継承の欠点が指摘されると分散オブジェクトのそれに倣った[[インタフェース (抽象型)|インターフェース]]の多重実装設計が取り上げられた。こうしてカプセル化の誕生と連動するようにしていわゆるオブジェクト指向の三大要素がやや漠然と確立されている。1996年にサン社がリリースした「[[Java]]」は三大要素が強く意識された[[クラスベース]]であり、その中の分散オブジェクト技術は[[JavaBeans|Beans]]と呼ばれた。類似の技術としてアップル社も[[MacOS]]上で[[Objective-C]]などから扱える[[Cocoa]]を開発している。また、1994年から96年にかけて「[[Python]]」「[[Ruby]]」「[[JavaScript]]」といったオブジェクト指向スクリプト言語がリリースされ、従来の[[クラスベース]]に対する[[プロトタイプベース]]という新しいオブジェクト指向スタイルを定着させている。1994年の[[ギャング・オブ・フォー (情報工学)|GOF]][[デザインパターン (ソフトウェア)|デザインパターン]]の発表と、1997年に[[Object Management Group|OMG]]が標準[[モデリング言語]]として採用した[[統一モデリング言語|UML]]は、オブジェクト指向プログラミングの標準化を促進させた。{{Quotation|''... there were two main paths that were catalysed by Simula. The early one (just by accident) was the bio/net non-data-procedure route that I took. The other one, which came a little later as an object of study was abstract data types, and this got much more play.''<br>(Simulaを触媒にした二本の道があった。最初の一本はバイオネットな非データ手法で僕が選んだ方。少し遅れたもう一本は抽象データ型、こっちの方がずっと賑わっている。)|Alan Kay}}

C++の創始者[[ビャーネ・ストロヴストルップ]]は、Smalltalkが目指したある種の理想の追求には興味が無く、現用としての実用性を重視した。そのため、C++の再定義した「オブジェクト指向」は既存言語の拡張としてオブジェクト指向機能を実装できることでブレイクスルーを迎え急速に普及する。Smalltalkが単なるメソッドの動的呼び出しをメッセージ送信に見立て、呼び出すメソッドが見つからないときのみメッセージをハンドリングできるようにした「省コスト版」の機構を発明し以降それを採用するに至った経緯も手伝って、'''メッセージ送信'''という考え方はやや軽視されるようになり、オブジェクト指向とはC++の再定義したものと広く認知されるようになった。

[[1980年]]代後半に次々と生まれたオブジェクト指向分析・設計論は、[[Smalltalk]]を源流とするオブジェクト指向を基に組み立てられた。そのころSmalltalkは商用展開こそされていたが広く普及しているとは言えず、一般には[[C++]]での[[実装]]が多くを占めた。しかしC++はSmalltalkと思想的にかなり異なる点や、同様のことを実現する際の実装面での複雑さや制約が問題とされた。このニーズを受けC++の提示した抽象データ型にクラスを適用する現実的な考え方と親しまれたALGOL系の構文を踏襲しつつ、内部的には柔軟なSmalltalkのオブジェクトモデルを採用し、'''メソッド'''などの一部用語やリフレクション、実行時動的性などSmalltalk色も取り入れた[[Java]]が注目を集めた([[1995年]]に登場。元々はモバイル機器向け言語処理系として開発された)。程なくSmalltalkやSELFで達成された[[仮想機械|仮想マシン(バイトコードインタープリタ)]]高速化技術の転用により実用的速度を得、バランス感覚に長けたJavaの台頭によって[[オブジェクト指向開発]]に必要な要素の多くが満たされ、[[1990年代]]後半からオブジェクト指向は広く普及するようになった。

== OOP言語一覧 ==
[[ファイル:History of object-oriented programming languages.svg|サムネイル|OOP言語の系譜|リンク=Special:FilePath/History_of_object-oriented_programming_languages.svg|代替文=]]
オブジェクト指向を総体的または部分的にサポートする機能を備えたプログラミング言語の公開は、1980年代後半から顕著となった。OOP言語の分類法は複数あるが、Smalltalkをルーツとするメッセージパッシングの構文が重視されてるか否かで大別される事が多い。そうでないものがOOP言語の主流となっており「C++」「Java」「C#」「Swift」などがその代表とされる。メッセージパッシングを重視するOOP言語には「Smalltalk」「Objective-C」「Self」などがある。言語仕様の中でオブジェクト指向の存在感が比較的高い代表的なプログラミング言語を以下に列挙する。


== 代表的なオブジェクト指向言語 ==
オブジェクト指向言語は、[[抽象データ型]]に準拠した[[クラスベース]]、{{仮リンク|メタオブジェクトプロトコル|en|Metaobject|label=}}を採用した[[プロトタイプベース]]、[[Smalltalk]]を規範にした[[メッセージパッシング|メッセージング]]ベースの三タイプに分類されるのが一般的である。[[クラスベース]]では「C++」「Java」「C#」が代表的である。[[プロトタイプベース]]では「Python」「JavaScript」「Ruby」が有名である。[[メッセージパッシング|メッセージング]]ベースでは「Smalltalk」「Objective-C」「Self」などがある。言語仕様の中でオブジェクト指向の存在感が比較的高い代表的なプログラミング言語は以下の通りである。
[[ファイル:History of object-oriented programming languages.svg|境界|中央|フレームなし]]
;[[Simula|Simula 67]] 1967年
;[[Simula|Simula 67]] 1967年
:1962年に公開された[[Simula]]の後継であり、[[クラス (コンピュータ)|クラス]]のプログラミング概念を導入した最初の言語である。現実世界の擬似モデルを観測するシミュレーション・プログラム制作用に開発されたもので、クラスをメモリに展開したオブジェクトはその観測対象要素なった。Simulaのクラスは、サブーチンに専用変数と補助プロシージャを加え機能的小型モジュールに近いものであったが、継承と仮想関数という先進的な設計を備えていた事でOOPの草分けと見なされるようになった。C++、Java、C#設計母体となった
:1962年に公開された[[Simula]]の後継バージョンであり、[[クラス (コンピュータ)|クラス]]のプログラ概念を導入した最初の言語である。物理モデルを解析するシミュレーション制作用に開発されたもので、クラスをメモリに展開したオブジェクトはその観測対象要素なった。Simulaのクラスは、一つのローカル変数構造複数のプロシージャをまとめミニモジュールと言えるものであったが、継承と仮想関数という先進的な設計を備えていた事でオブジェクト指向言語の草分けと見なされるようになった。[[クラスベース]]源流である
;[[Smalltalk]] 1972年
;[[Smalltalk]] 1972年
:[[メッセージパッシング]]のプログラミング概念を導入した最初の言語。数値、真偽値から変数、構造体、コードブロック、メタデータまでのあらゆる要素をオブジェクトとする概念を編み出した最初の言語で。オブジェクト指向という言葉はSmalltalk開発者がその言語設計を説明する中で生み出された。オブジェクトの基礎的な振る舞いを規定する限られた予約語の他は、オブジェクトとメッセージのやり取りで制御構造含めたあらゆるプロセスを表現出来た。専用のランタイム環境上でプログラムを実行する設計を応用して動的な多態性とセキュリティに繋がるモニタリング実現した。これは後に仮想マシンと呼ばれるものとなり、JavaやC#踏襲された
:[[メッセージパッシング|メッセージング]]のプログラ概念を導入した最初の言語。数値、真偽値、文字列から変数、コードブロック、メタデータまでのあらゆるプログラム要素をオブジェクトとするアイディアを編み出した最初の言語であり、[[プロトタイプベース]]の源流にもなった。オブジェクト指向という言葉はSmalltalkの言語設計を説明する中で生み出された。オブジェクトメッセージを送るという書式であらゆるプロセスを表現することが目標にされている。動的ディスパッチと[[ダイナミックバインディング|動的バインディング]]相当の機構である[[メッセージ転送|メッセージレシーバー]]と[[委譲|デリゲーション]]は、後年の[[デザインパターン (ソフトウェア)|デザインパターン]]のモデルにもされた。GUI運用環境に統合された専用のランタイム環境上で動作させる設計も模範にされ、これは後に[[仮想マシン]]や[[仮想実行システム]]と呼ばれるものになる
;[[C++]] 1983年
;[[C++]] 1983年
:[[C言語]]にOOPデザインを追加したもの。Simulaの影響を受けている。[[クラス (コンピュータ)|クラス]]のメカニズムが備えられてカプセル化、継承、多態性といったOOP仕様を実装している。[[テンプレート (プログラミング)|テンプレート機能]][[例外処理]]、演算子オーバーロードを応用した関数オブジェトなど様々なプログラミングパラダイムも導入され。元がC言語であるため、OOPから逸脱したコーディングも多用できる点が物議を醸したが、その是非はプログラマ次第であるという結論に落ち着いた。
:[[C言語]]に[[クラスベース]]のオブジェクト指向を追加したもの。Simulaの影響を受けている。[[静的型付け]]の[[クラス (コンピュータ)|クラス]]が備えられてカプセル化、継承、多態性の三仕様を実装している。カプセル化ではアクセス修飾子とフレンド指定子の双方から可視性を定義できる。継承は多重継承、オーバーライド制約用の継承可視性、[[菱形継承問題]]解決用の[[仮想継承]]も導入されている。多態性は[[仮想関数]]によるサブタイプ多相、[[テンプレート (プログラミング)|テンプレートクラス&関数]]によるパラメトリック多相、[[多重定義|関数&演算子オーバーロード]]によるアドホッ多相が導入されている。元がC言語であるため、オブジェクト指向から逸脱したコーディングも多用できる点が物議を醸したが、その是非はプログラマ次第であるという結論に落ち着いた。
;[[Objective-C]] 1984年
;[[Objective-C]] 1984年
:[[C言語]]をOOPデザイしたもの。こちらはSmalltalkの影響を受けており、それに準じた[[メッセージパッシング]]と[[リフレクション (情報工学)|リフレクション]]のメカニズムが備えられOOP的には前述のC++よりも正統であると見なされた。制御構文が追加され、メッセージの仕様やや簡素化されるなど実践上の便宜が図られており、Smalltalkよりもコーディングし易くなった。
:[[C言語]]に[[メッセージパッシグ|メッセージング]]ベースのオブジェクト指向を追加したもの。こちらはSmalltalkの影響を受けており、それに準じた[[メッセージパッシング]]の書式が備えられた。メッセージを受け取るクラスの定義による[[静的型付け]]と共に、メッセージを[[委譲]]するオブジェクト実行時決定による[[動的型付け]]も設けられているオブジェクト指向的にはC++よりも正統と見なされた。[[制御構造|制御構造]]が追加され、メッセージ構文平易化されており、Smalltalkよりも扱いやすくなった。
;[[Object Pascal]] 1986年
;[[Object Pascal]] 1986年
:[[Pascal]]にクラスベースのオブジェクト指向を追加したもの。当初はモジュールのデータ隠蔽的なカプセル化、単一継承、仮想関数による多態性という基本的なものだった。静的型付け重視である。[[ニクラウス・ヴィルト|ヴィルト]]監修の[[アップル (企業)|アップル社]]による初回バージョンを土台にして様々な企業団体による派生版が公開されており、その特徴と機能追加も様々である。
:[[Pascal]]をOOPデザイン化したもの。
;[[Eiffel]] 1986年
;[[Eiffel]] 1986年
:[[C++]]の柔軟性と融通性とは正反対のオブジェクト指向言語。[[クラスベース]]で[[静的型付け]]重視である。[[契約プログラミング|契約による設計]]に基づく[[表明|アサーション]]の挿入でクラスの状態および演算用の引数と返り値を細かくチェックできる。[[例外処理]]も備えられている。クラスメンバ(フィーチャー)はデータ、アクセッサ、ミューテイタの三種限定で[[多重定義|オーバーロード]]はできない。カプセル化の可視性は自身に依存するクラス(クライアント)を定義する形で決められる。多重継承可能であり、クラス間の繋がりを[[仮想継承]]機能、各種[[オーバーライド]]指定子、名前衝突を解決するリネーミング機能などで綿密に設定できる。多態性は[[仮想関数|延期関数/手続き]](サブタイプ多相)と[[ジェネリックプログラミング|ジェネリシティ]](パラメトリック多相)である。[[ガーベジコレクション]]機能が初めて導入されたオブジェクト指向言語でもある。
:[[Pascal]]をベースにしてOOPデザイン化し、また[[ジェネリックプログラミング]]を追加した。型付けは静的に限られ、非参照データを自動解放する[[ガーベジコレクション|ガーベジコレクタ]]を持ち、多重継承時の問題を回避する仕組みや例外処理など高い堅牢性を備えた。これらは後のJavaやC#の手本となった。
;[[Self]] 1987年
;[[Self]] 1987年
:メッセージパッシングの構文が中心となっている。動的な多態性を重視した言語であり、従来の[[クラスベ]]のオブジェクト設計に対して、テム側が用意オブジェクトを複製して任意の拡張を施す[[プロトタイプベース]]のデザンを初めて実装した。Smalltalkと同様に専用のランタイム環境で実行されたがこれも実面で初となる[[実行時コンパイラ]](''just-in-time compiler'')の機能が備えられて速度面でも画期的ななった。
:[[メッセージパッシング|メッセジング]]ベースのオブジェクト指向言語でSmalltalkの方言として開発された。それ故にプロトタイプからプロトタイプを派生させまたインタンスを複製てそれにプロパティとメソッドを[[ダイナミックバインディング|動的バインディング]]できるというメタオブジェクトプロトコルも忠実に実装された。[[プロトタイプベース]]というパラダムはこのSelfから認知されるようになっ。[[動的型付け]]重視である。Smalltalkと同様に専用のランタイム環境で実行され、GUI運環境の構築も目標にしていた。Selfのランタイム環境は[[実行時コンパイラ]]機能を初めて実装したことで知られており画期的な処理速度を実現している。こ技術は[[Java仮想マシン]]の土台になった。
;[[CLOS]] 1988年
;[[Common Lisp]]([[CLOS]]) 1988年(ANSI規格化は1994年)
:[[クラスベース]]のオブジェクト指向。メソッド記述の関数呼び出し形式への統合、[[多重ディスパッチ]]、クラスの動的な再定義等を特徴とする。
:[[Common Lisp]]をOOPデザイン化したもの。
;[[Python]] 1990
;[[Python]] 1994
:[[プロトタイプベース]]のオブジェクト指向スクリプト言語。[[基本データ型]]や[[コンテナ (データ型)|コレクション型]]などよく使われるデータ要素を全て組み込みのオブジェクトにしている。それらは[[手続き型プログラミング|手続き型]]スタイルでも気軽に扱える。コレクション型を扱うのに適した[[関数型プログラミング|関数型]]構文も導入されている。関数/変数のオブジェクトは自由にプロパティとメソッドを付け足し付け替え可能である。オブジェクトは[[ダックタイピング]]で型判別されるので変数/関数の型宣言と型注釈は撤廃されている。ゆえに[[動的な型付け|動的型付け]]重視である。Pythonのプロトタイプはクラスと呼ばれている。多重継承可能であり親クラス要素のサーチ順序はC3線形化で解決されている。多態性は事実上メソッドの動的バインディングになっている。カプセル化は軽視されている。後期バージョンで型ヒントが追加され、それに伴い[[ジェネリクス]]も導入された。
:[[インタプリタ]]式で動作する。言語仕様を簡素化し自動メモリ管理機能を実装して扱いやすく理解しやすいOOPを目指している。後のOOPスクリプト言語の手本となった。
;[[Java]] 1995年
;[[Java]] 1995年
:[[C++]]をモデルにしつつ堅牢性とセキュリティを重視した[[クラスベース]]のオブジェクト指向言語。静的型付け重視である。パッケージ中心のカプセル化、単一のみの継承、仮想関数と多重実装可な[[インタフェース (抽象型)|インターフェース]]による多態性と、基本に忠実なクラスベースである。C++風の[[ポインタ (プログラミング)|ポインタ]]と値型インスタンスは除外されて参照型インスタンスに統一した。[[例外処理]]を整備し[[演算子オーバーロード]]を除外した。オブジェクト指向と[[マルチスレッド]]の調和が図られ、[[ソフトウェアコンポーネント|コンポーネント指向]]による動的クラスローディングの存在感が高められている。クラスメタデータを操作できる[[リフレクション (情報工学)|リフレクション]]は初期から採用された。中期から[[ジェネリクス]](パラメトリック多相)と[[アノテーション|メタアノテーション]](アドホック多相)が導入され、ラムダ式と関数型インターフェースを軸にした[[関数型言語|関数型構文]]も採用された。[[仮想マシン]]上で実行される。[[仮想マシン]]と[[ガーベジコレクション]]の技術は比較的高度と見なされている。
:堅牢性と安全性を重視したOOP言語。その二つの理念を実現するために、仮想マシン上の実行、ガーベジコレクタ、例外処理などを採用し、ポインタと直アドレス変数、多重継承、ジェネリックプログラミング、演算子オーバーロードなどを破棄した。破棄部分についてはその埋め合わせの設計も備えられた。[[クラス (コンピュータ)|クラス]]のメカニズムを中心にしたOOPであるが、様々なプログラミングパラダイムも追加されている。非常に整えられたハイブリッドOOP言語である。
;[[Delphi]] 1995年
;[[Delphi]] 1995年
:[[Object Pascal]]を発展させたものでデータベース操作プログラム開発などを主な用途した。一時期Javaの対抗馬なった。
:[[Object Pascal]]を発展させたもの。それと同様にこちらも基本に忠実なクラスベース静的型付け重視であった。当初はデータベース操作プログラム開発を主な用途て公開された。クラスとレコード([[構造体]])に同等の比重が置かれていた。一時期Javaの対抗馬なった。
;[[Ruby]] 1995
;[[Ruby]] 1996
:[[Python]]を意識して開発されたオブジェクト指向スクリプト言語。[[Smalltalk]]を一つの理想にしてより万人向けの言語を目指し、動的型付けを重視している。日本で誕生してグローバル化したプログラミング言語である。[[LISP]]とSmalltalkのメタプログラミング的なオブジェクト指向から、Pythonと[[JavaScript]]のプロトタイプベースなオブジェクト指向までのスタイルとコーディング手法を幅広く取り入れている。
:OOPデザインされたスクリプト言語である。[[インタプリタ]]式で動作する。スクリプトでありながら、クラス、マルチスレッド、例外処理、そして[[ソフトウェアコンポーネント]](モジュール)を扱える[[Mixin]]といった利便性の高い機能も備えている。
;[[JavaScript]] 1996年
;[[JavaScript]] 1996年
:[[プロトタイプベース]]のオブジェクト指向スクリプト言語。型宣言と型注釈を撤廃して[[ダックタイピング]]する[[動的な型付け|動的型付け]]重視である。すべてをオブジェクトにする[[Smalltalk]]の思想に忠実な言語であり、[[Python]]と似ているがそれよりも[[プロトタイプベース]]性質と[[関数型プログラミング]]性質を追求している。定数、変数、構造体、関数などが全て同性質のオブジェクトにされており、プロパティとメソッドを自由に付け足したり付け替えできるようにデザインされている。関数オブジェクトの構築と用い方がプログラミング上のキーポイントになっており、[[クロージャ]]、[[高階関数]]、[[第一級関数]]、デコレータ、[[パイプライン処理|パイプライン]]といった多種多様な働き方とその組み合わせを柔軟に表現できる。[[ウェブアプリケーション|WEBアプリケーション]]開発を主な用途にして公開されたのでオブジェクトは[[GUI]]パーツの構築にも最適化されている。[[ECMAScript]]として標準化されており、2015年版からは[[クラスベース]]向けの構文もサポートするようになった。
:[[ウェブアプリケーション]]開発を主な目的とするOOPスクリプト言語。主に[[プロトタイプベース]]でオブジェクトを扱う事でコーディングを簡便にしている。[[ECMAScript]]として標準化されている。ECMAScript 2015ではクラス構文をサポートするようになった。
;[[C Sharp|C#]] 2000年
;[[C Sharp|C#]] 2000年
:[[Java]]を強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。Javaよりも[[マルチパラダイムプログラミング言語|マルチパラダイム]]の性質が強化されている。C++譲りの柔軟性と融通的を残しながら様々な[[糖衣構文]]サポートも加えてコーディング上の利便性がより高められている。[[マルチスレッド]]仕様も整備されている。アドホック多相では拡張メソッド、インデクサ、演算子オーバーロードなどを備えている。パラメトリック多相では[[共変性と反変性 (計算機科学)|共変/反変]]も扱える[[ジェネリクス]]を備えている。サブタイプ多相はクラスは単一継承でインターフェースは多重実装と基本通りである。[[関数型言語|関数型構文]]も整備されており、特にメソッド参照機能であるデリゲートの有用性が高められている。デリゲートは[[イベント駆動型プログラミング|イベント駆動構文]]の平易な表現も可能にしている。基本は[[静的型付け]]であるが、動的束縛型と[[ダックタイピング]]による[[動的型付け]]の存在感が高められているので漸進的型付けの言語と見なされている。[[.NET Framework]]([[共通言語基盤]]=仮想実行システム)上で実行される。
:[[Java]]を強く意識して開発されたOOP言語。[[.NET Framework]]などの[[共通言語基盤]]上で実行される。Javaと同等または部分的に拡張させたスタイルを持ち、こちらもよく整えられたハイブリッドOOP言語として知られる。
;[[Scala]] 2003年
;[[Microsoft Visual Basic .NET|Visual Basic.NET]] 2002年
:[[クラスベース]]のオブジェクト指向と[[関数型プログラミング]]を融合させた言語。[[クラス (コンピュータ)|クラス]]機構と関数型の[[型システム]]に同等の比重が置かれており静的型付け重視である。[[ミックスイン]]相当の[[トレイト]]と、[[共変性と反変性 (計算機科学)|共変/反変]]および抽象タイプメンバを扱える[[ジェネリクス]]を連携させた多態性が重視されておりオブジェクトを様々に[[派生型|派生型付け]]できる。シングルトンオブジェクトの役割が形式化されて従来のクラス静的メンバの新解釈にも用いられている。専用の定義書式により[[イミュータブル]]なオブジェクトが重視されている。上述の派生型付けスタイルとオブジェクト引数の[[逆写像|抽出]]構文と[[パターンマッチング|パターンマッチング式]]の併用連鎖計算は[[モナド (プログラミング)|モナド]]を彷彿とさせて独特の関数型スタイルを表現できる。[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。
:[[Microsoft Visual Basic|Visual Basic]]をOOPデザイン化したもの。[[.NET Framework]]などの[[共通言語基盤]]上で実行される。
;[[Ceylon]] 2011年
:[[Java]]を元に開発され、その長所と短所を見直しつつ再設計されたOOP言語。Javaの改造版である。また[[JavaScript]]にもコンバートできる。
;[[Kotlin]] 2011年
;[[Kotlin]] 2011年
:静的型付けの[[クラスベース]]のオブジェクト指向であるが、[[手続き型プログラミング]]に回帰しており、クラス枠外の関数とグローバル変数の存在感が高められている。クラスはpublicアクセスとfinal継承がデフォルトにされて、カプセル化と継承が公然と軽視されている。これによりインスタンスは手続き型の関数の対象値としての役割が強められ、その操作をサポートする関数型構文も導入されている。仮想関数と抽象クラスによる多態性は標準通りである。[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。
:[[Javaバイトコード]]を出力し、[[Java仮想マシン]]上で動作するJavaテクノロジー互換OOP言語である。OOPでありながらグローバル関数および変数の使用も容認されており、オブジェクト指向プログラミングを手続き型プログラミングのスタイルに崩したかのようにデザインされている。
;[[TypeScript]] 2012年
:[[JavaScript]]を強く意識してマイクロソフト社が開発したオブジェクト指向スクリプト言語。JavaScriptのプログラムを静的型付けで補完した言語である。[[クラスベース]]向けの構文と、[[関数型プログラミング]]の[[型システム]]のスタイルが加えられている。特に後者の性質が強調されている事から静的型付け重視である。継承構造によるサブタイプ多相はほぼ除外されており、[[ジェネリクス]]と型アノテーションでオブジェクトを扱うというパラメトリック多相とアドホック多相を重視するデザインになっている。オブジェクト指向ではあるが関数型の性格が強めである。
;[[Swift (プログラミング言語)|Swift]] 2014年
;[[Swift (プログラミング言語)|Swift]] 2014年
:[[Objective-C]]を発展させたものであるが、メッセージ構文は破棄されており、クラスベースのオブジェクト指向になっている。オブジェクトの[[イミュータブル|イミュータブル性]]重視の構文が採用されている。プロテクト可視性の削除によってクラスの縦並びの継承は軽視されており、プロトコルの横並びの多重実装を重視している。プロトコルは[[インタフェース (抽象型)|インターフェース]]と[[ミックスイン]]の中間的機能であり、インスタンスはプロトコルを基準にして型分類され、また抽象化される。プロトコルと[[ジェネリクス]]の連携による多態性が重視されている。モジュールの動的ローディングは不透明型の仕組みで補完されている。[[静的型付け]]重視である。
:高度に整えられたマルチパラダイムプログラミング言語。クラスのメカニズムをベースにしたオブジェクト指向プログラミングも導入されている。


== OOP言の仕組み ==
== と解説 ==
;[[クラス (コンピュータ)|クラス]]
オブジェクト指向プログラミング言語は、相互に'''[[#メッセージ|メッセージ]]'''を送りあう'''[[オブジェクト (プログラミング)|オブジェクト]]'''の集まりとして[[プログラム (コンピュータ)|プログラム]]を構成することができる仕組みを持つ。
:(''class'')の仕組みを中心にしたオブジェクト指向を[[クラスベース]]と言う。クラスはデータとメソッドをまとめたものであり、[[プログラム意味論|操作的意味論]]を付加された静的[[構造体|レコード]]とも解釈される。クラスはインスタンスのひな型であり、インスタンスはクラスを実例化(量化)したものである。クラスはカプセル化、継承、多態性の三機能を備えていることが求められている。カプセル化は[[This (プログラミング)|this参照]]の仕組みの実装およびデータとメソッドの可視性を指定できる機能である。継承は自身のスーパークラスを指定できる機能である。多態性は[[オーバーライド]]と[[仮想関数テーブル]]を処理する機能である。コンストラクタとデストラクタの実装も必要とされている。前者はインスタンス生成時に、後者はインスタンス破棄時に呼び出されるメソッドである。
そのために、少なくともオブジェクトについての3つの仕組みと、オブジェクトの管理についての3つの仕組みが必要となる。
;プロトタイプ
:(''prototype'')の仕組みを中心にしたオブジェクト指向を[[プロトタイプベース]]と言う。プロトタイプとは識別名&中間参照ペアの集合体を指す。この集合体は一般にフレームと呼ばれる。識別名&中間参照ペアの割り当て箇所は一般にスロットと呼ばれる。スロットにはデータとメソッドの識別名&中間参照ペアが代入されるので、プロトタイプはクラスと同様にデータとメソッドをまとめたものになる。プロトタイプは言語によってはクラスと呼ばれている。プログラマはシステムが提供する基底プロトタイプに、自由にデータとメソッドを付け足して任意の派生プロトタイプを作成できる。プロトタイプは「型」相当であり、それを複製する方式で生成されるインスタンスは「値」相当である。データとメソッドはその参照にインスタンスを必要とするものと、しないものに分かれる。前者はインスタンスメンバ、後者は静的メンバに相当するものである。インスタンスにも自由にデータとメソッドを付け足すことができる。インスタンスはそのプロトタイプへの参照を保持しており、プロトタイプはその親プロトタイプへの参照を保持している。これは継承相当の機能になっている。インスタンスへの自由なメンバ付け替えは多態性相当の機能になっている。ただしプロトタイプは動的な[[関数型言語]]由来の仕様なのでクラスベースOOPの三大要素とはまた違った視点から眺める必要がある。
;[[メッセージ (コンピュータ)|メッセージ]]
:オブジェクト指向で言われるメッセージ(''message'')とは、オブジェクトの呼び出し側と呼び出される側の間であらゆる事柄が実行時に決められる仕組み全般を指す用語である。関数名の解釈、引数構成、返り値構成、関数名対応プロセス所有の是非、委譲先、同期/非同期タイミングといったものが実行時のその都度に決められる。実行時に解釈される関数名文字列はセレクタと呼ばれる。これは無制限に柔軟な仕様の関数呼び出しと考えてもよく、その実装方法の明確な定義は不可能である。代表例を挙げると分散オブジェクトや分散システムで用いられているメッセージパッシングは、関数名も実行時に解釈できる引数要素にした仕組みである。Smalltalk指向の言語に導入されているメッセージレシーバーとメソッドミッシングでは、特定のセレクタに対応するプロセスをコンパイル時定義できるようにして自動実行時選択されるようになっており、プロセス未定義セレクタだけが実行時解釈される仕組みになっている。このコンパイル時定義のセレクタプロセスをメソッドと呼んだ。OOPでメンバ関数をわざわざメソッドと呼ぶのはメッセージパッシング由来のこうした経緯からである。アラン・ケイはメッセージング(''messaging'')というより遠大な構想を持っていた。
;[[インスタンス]]
:(''instance'')はクラスベースではクラスを実例化(量化)したものであり、実装レベルで言うとデータ群と仮想関数テーブルをメモリ上に展開したものになる。プロトタイプベースではプロトタイプを複製する方式で生成されたオブジェクトを指す。実装レベルで言うとメモリ上に展開された識別名&中間参照ペアの動的配列になる。
;[[フィールド (計算機科学)|データメンバ]]
:(''data member'')はクラスに属する変数。データ(''data'')とも略称される。言語によってフィールド(分節)、プロパティ(特性)、アトリビュート(属性)、メンバ変数と呼ばれる。データは、クラスデータとインスタンスデータに分かれる。クラスデータは静的データとも呼ばれる。その中で定数化されたものはクラス[[定数 (プログラミング)|定数]]と呼ばれる。クラスデータはクラス名の名前空間でスコープされたグローバル変数と同じものであり、プログラム開始時から終了時まで確保される。インスタンスデータはインスタンス生成時にメモリ上に確保されるものであり、その破棄時に消滅する。インスタンスデータの参照にはそのthis参照が必要である。プロトタイプベースでは、プロトタイプで定義されたデータでそのアクセスにインスタンス(self)を必要としないものが静的データになる。
;[[メソッド (計算機科学)|メソッド]]
:(''method'')はクラスに属する関数。言語によってはメンバ関数、メンバ手続きとも呼ばれる。データの参照に特化したものはゲッター(''getter'')アクセッサ(''accessor'')と呼ばれる。データの変更に特化したものはセッター(''setter'')ミューテイタ(''mutator'')と呼ばれる。メソッドは、クラスメソッドとインスタンスメソッドに分かれる。クラスメソッドは静的メソッドとも呼ばれる。クラスメソッドはクラス名の名前空間でスコープされたグローバル関数と同じものである。インスタンスメソッドを呼び出すにはそのthis参照が必要である。プロトタイプベースでは、プロトタイプで定義されたメソッドでそのアクセスにインスタンス(self)を必要としないものが静的メソッドになる。
;[[コンストラクタ]]
:(''constructor'')はインスタンス生成時に呼び出されるそのクラスのメソッドである。インスタンスデータを任意の値で初期化するためのものであるが、その他の初期化コードも記述できる。プロトタイプベースではシステム提供プロトタイプが保持する生成用メソッドまたは生成用のグローバル関数がコンストラクタ相当になる。
;[[デストラクタ]]
:(''destructor'')はインスタンス破棄時に呼び出されるそのクラスのメソッドである。インスタンス破棄の影響を解決する任意の後始末コードを記述できる。インスタンスの破棄は占有メモリの解放を意味する。なお、ガーベジコレクタ実装言語ではファイナライザになっている事がある。プログラマが呼び出すデストラクタの方はその終了がメモリ解放に直結しているのに対し、ガーベジコレクタが呼び出すファイナライザの方はそうではない。
;[[This (プログラミング)|this参照]]
:(''this'')は言語によっては「self」や「me」とも呼ばれる。<code>instance.method()</code>の書式で呼び出されたメソッド内で、そのインスタンスのメンバを暗黙アクセスできるようにするための仕組みである。<code>instance</code>のアドレスが暗黙引数として<code>method</code>に渡されて、その<code>method</code>内で<code>this</code>となる。インスタンスのメンバアクセス時はこの<code>this</code>が自動的に付加され、例えば<code>data</code>がシステム内では<code>this.data</code>のように変換されている。メソッドはインスタンスの実体化元(量化元)クラスで定義されているものである。これは、データにメソッドを付属させるカプセル化を実現するための仕組みである。this参照に対するsuper参照(''super'')は、サブクラスのインスタンスメソッド内で用いられるものであり、直上スーパークラスのデータ/メソッドにアクセスするための参照である。オーバーライドやドミナンスを無視してスーパクラスのメンバを呼び出すための仕組みである。
;アクセスコントロール
:(''access control'')は、カプセル化の情報隠蔽に基づいた機能であり、クラス内のデータとメソッドの可視性を決定する。可視性とはそれにアクセス(参照/変更)できる範囲を意味する。これにはレキシカルスコープ基準とクライアント基準の二通りがあるが、前者の方が一般的である。広く使われているレキシカルスコープ基準の可視性は、プライベート、プロテクト、パブリックの三種が基本である。プライベートは同クラス内のメンバからのみ、プロテクトは同クラス内と派生クラス内のメンバからのみ、パブリックはどこからでもアクセス可能である。クライアント基準の可視性は、自身メンバへのアクセスを許可するクライアントクラス(フレンドクラス)を定義する方法で決められる。そのクライアントの許可は同時にその派生クラスの許可も兼ねている事が多く、継承によるクラス群の一括定義を可能にする。
;コピーコンストラクタ
:(''copy constructor'')は、メソッドの引数に対する値インスタンスの値渡しの時に呼び出されるコンストラクタである。値渡しはインスタンス内容全体のメモリコピーであり、基本データ型では特に問題は生じないが、そうでないクラスのインスタンスでは例えばあるリソースへの参照を保持している場合に好ましくない保持重複が発生する事になる。呼び出されたコピーコンストラクタは値インスタンスを受け取り、単純コピーが許されない部分に任意の処理を施して生成した値インスタンスのコピーを引数へと渡す。
;[[オーバーロード]]
:(''overloading'')は、同じメソッド名(返り値の型+メソッド名)にそれぞれ異なるパラメータリスト(引数欄)を付けたものを列挙してメソッドを多重定義する仕組みを指す。[[演算子]]もオーバーロード対象であり、[[単項演算子]]なら一つの引数の型、[[二項演算子]]なら二つの引数の型を多重定義することで演算対象の値の型ごとに計算内容をカスタマイズできる。任意個数の引数を多重定義できる( )演算子は、[[クロージャ]]または[[関数オブジェクト]]の表現に用いられる。


;[[オーバーライド]]
;オブジェクトの仕組み
:(''method overriding'')は、基底クラスで定義されたメソッド名義の呼び出しを、派生クラスで実装されたメソッド内容の実行につなげる機能である。これは基底メソッドを派生メソッドで上書きすると形容される。オーバーライドされた基底メソッドの内容はスルーされて派生メソッドの内容が実行される。メソッドシグネチャ(返り値の型+メソッド名+各引数の型と個数)が完全一致している基底側が派生側でオーバーライドされる。オーバーライド指定は、基底側のメソッドをvirtualやabstractで修飾する方式と、派生側のメソッドをoverrideやredefineで修飾する方式がある。前者では基底側でオーバーライド可否の定義が固定されるのに対して、後者では派生側で再定義できる。finalで修飾されたメソッドは再定義不可のオーバーライドの拒絶になる。オーバーライドメソッドの呼び出しは、基底クラスの型に代入された派生クラスのインスタンスで行われる。オーバーライドによって呼び出される内容が多相化されたメソッドは[[仮想関数]]と呼ばれる。[[仮想関数テーブル]](''virtual method table'')はその多相化のための仕組みであり、メソッドシグネチャとメソッド内容アドレスがマッピングされている。
:* オブジェクトに蓄えられる情報、データを表現する仕組み。
;ドミナンス
:* 他のオブジェクトにメッセージを配送する仕組み。
:(''dominance'')は言語によってハイディング(''hiding'')マスキング(''masking'')とも呼ばれる。継承による階層的クラス構造において、サブクラスのメンバがスーパークラスの同名のメンバを隠していることを指す。親クラスのAメソッドを子クラスが同名Aメソッドでドミナンスした場合、子の型で参照しているインスタンスはそこでAのサーチが止まって子Aが呼び出される。ただし親の型で参照すれば親Aを呼び出せる。オーバーライドと異なり、参照する型でインスタンスの振る舞いを変えるための単純な仕組みでもある。
:* 受け入れ可能な各種メッセージに対応して、処理する事柄を記述する仕組み([[メソッド (計算機科学)|メソッド]])。
;[[仮想継承]]
:
:(''virtual inheritance'')は、多重継承での[[菱形継承問題]]を回避するための仕組みである。菱形継承問題とは共にAクラスを親とするBクラスとCクラスの双方を継承した場合に、その継承構造上でAクラスが二つ重なって存在することになる不具合である。仮想継承では専用のテーブルが用意されて、そこでクラス名が参照アドレスにマッピングされる。BクラスからのAクラスと、CクラスからのAクラスは共に同じ参照アドレスをマッピングするのでAクラスはひとつにまとめられる事になる。同時に一度辿ったクラスは省略される事にもなる。
;オブジェクトを管理する仕組み
;MRO
:* オブジェクト間の関係を整理分類して系統立てる仕組み。
:メソッド解決順序(''method resolution order'')は、多重継承時の親クラスの巡回順序を定義するものである。参照されたメソッドが自クラスにない場合はその親クラスを巡回してサーチされる。メソッドはクラスメンバと読み替えてもよい。これは[[深さ優先探索|深さ優先検索]](''deep-first'')と[[幅優先探索|幅優先検索]](''breadth-first'')に分かれるが、オブジェクトの構造概念から深さ優先の方が自然とされている。従って一般的な多重継承では深さ優先検索が用いられて親クラスの重複は仮想継承で解決されている。しかし詳細は割愛するが、仮想継承部分の巡回順序に不自然さを指摘する意見もあったので、これを解決するために深さ優先と幅優先をミックスしたC3線形化(''C3 linearization'')というメソッド解決順序が考案された。C3線形化では親クラスの重複部分に対してのみ幅優先検索を適用することで、仮想継承を用いることなく菱形継承問題も自然に解決されている。
:* 必要なオブジェクトを作成・準備する仕組み。
;[[抽象クラス]]
:* 不要なオブジェクトを安全に破棄する仕組み。
:(''abstract class'')は、全部または一部のメソッドが抽象化されているクラスを意味する。即ち抽象メソッドを持つクラスである。抽象メソッド(''abstract method'')は、メソッドシグネチャ(返り値の型+メソッド名+各引数の型と個数)だけが定義されてコード内容が省略されているメソッドである。抽象クラスはインスタンス化できないので継承専用になる。抽象メソッドはそのサブクラスの方でコード内容が実装されてオーバーライドされる。


{{型システム}}
これらをどのように言語の要素として提供し、どのような[[機械語]]コードで実現するかによって様々な[[オブジェクト指向プログラミング言語]]のバリエーションが生まれる。以下、オブジェクト指向プログラミング言語が提供する様々な要素が上記の仕組みをどのように実現しているかについて概観する。
;[[インタフェース (抽象型)|インターフェース]]
:(''interface'')はプログラム概念と機能名の双方を指す用語である。言語によってはプロトコルと言われる。抽象メソッドと実体メソッドをメンバにする純粋抽象〜半抽象クラスを意味する。一般的にデータはメンバにされない。クラスの振る舞い側面を抜き出した抽象体である。クラスによるインターフェースの継承は実装と呼ばれる。多重実装可が普通である。ミックスインとの違いは、抽象階層に焦点が当てられている事であり、直下の実装オブジェクトを共通の振る舞い側面でまとめることがその役割である。インターフェースは自身の[[下位概念]]である実装継承オブジェクトをグループ化できる。{{仮リンク|記名的型付け|en|Nominal type system|label=}}に準拠しているのでインターフェースの実装の明記が振る舞い側面の識別基準になる。インターフェースは抽象メソッド主体なので多重継承時のメンバ名の重複はあまり問題にならない。共通の実装メソッドに集約されるからである。インターフェースは非インスタンス対象である。
;[[ミックスイン]]
:(''mixin'')はインターフェースに似たプログラム概念を指す用語である。機能名は言語によって[[トレイト]]、プロトコル、構造型(''structural type'')と言われる。抽象メソッドと実体メソッドとデータをメンバにする継承専用クラスを意味する。クラスを特徴付けるための構成パーツである。クラスによるトレイトの継承は実装と呼ばれる。多重実装可が普通である。インターフェースとの違いは、トレイトの実装階層に焦点が当てられている事であり、オブジェクトを所有メンバで特定してまとめることがその役割である。トレイトは自身の[[上位集合]]である実装継承オブジェクトをグループ化できる。{{仮リンク|構造的型付け|en|Structural type system|label=}}に準拠しているので所属メンバ構成自体がトレイト等価性の識別基準になる。これはトレイト実装を明記していなくても、そのトレイトが内包する全メンバを所持していれば同じトレイトと見なされることを意味する。トレイトは合成や交差が可能である。トレイトは多重継承時のメンバ名重複の際にその参照の優先順位に注意する必要がある。トレイトは非インスタンス対象である。
;型イントロスペクション
:''(type introspection'')は一般に実行時型チェックと呼ばれるものである。プログラマが認知できない形で[[コンパイラ]]または[[インタプリタ]]が別途実装している[[インスタンス]]の型情報を、実行時にその都度参照してインスタンスの型を判別する仕組みである。[[静的型付け]]下では専用の実行時型チェック構文(instanceofやdynamic_cast)によって型判別し、ダウンキャストなどに繋げられる。[[動的型付け]]下では変数への再代入時や関数への引数適用時にランタイムシステムが自動的に型判別し、[[多重ディスパッチ]]などに繋げられる。型イントロスペクションでは型情報のタグ識別子が判定基準になっているので{{仮リンク|記名的型付け|en|Nominal type system|label=}}の考え方に準じている。
;[[ダックタイピング]]
:''(duck typing'')は、特定のメソッド名(メソッドシグネチャ)またはプロパティ名(データ名)の識別子を持っているかどうかでインスタンスをその都度分類する仕組みである。これはその場限りの型判別と言えるものである。判別されたインスタンスは自身が持つとされたメソッドまたはプロパティを呼び出される事になる。[[動的型付け]]の機能であり、ダックタイピングでは型情報の構成内容が判定基準になっているので{{仮リンク|構造的型付け|en|Structural type system|label=}}の考え方に準じている。
;[[型推論]]
:オブジェクト指向下の型推論''(type inference'')は、型宣言ないし型注釈を省略して定義された変数の「型」が自動的に導き出される機能を指す。型はクラスと同義である。[[静的型付け]]の機能であり、コンパイラまたはインタプリタがソースコードをあらかじめ解析し、初期値の代入を始めとしたその変数の扱われ方によって型を導き出す。ここで導き出される「型」とは他の変数への代入可能性や、関数の引数への適用可能性といったあくまで等価性の基準で決められるので、プログラマが人為的な意味付けによる型定義を重視している場合は予期せぬ結果が発生することにもなる。型推論は{{仮リンク|推論的型付け|en|Inferred typing|label=}}とも呼ばれ、普通に型宣言と型注釈を用いる{{仮リンク|明示的型付け|en|Manifest typing|label=}}の対極に位置付けられるが、昨今のオブジェクト指向言語では双方を併用するのが主流になっている。


;[[メタクラス]]
=== オブジェクトの概念と実装 ===
:(''metaclass'')は{{仮リンク|メタオブジェクトプロトコル|en|Metaobject|label=}}に準拠した機能名であり、実装方式は言語毎に違いがある。メタクラスは、クラスのデータ、メソッド、スーパークラス、内部クラスなどの定義情報を記録した[[メタデータ]]である。クラスベースのメタクラス機能は、実装レベルではシステム側が用意している特別なシングルトンオブジェクトと考えた方が分かりやすい。それにはほとんどの場合システム側が提供する抽象インターフェースを通してのみアクセスできる。メタクラス内容を閲覧/変更できる機能はリフレクションと呼ばれる。プロトタイプベースでは、インスタンスの複製元であるプロトタイプまたはクラスがメタクラス機能も備えており、データとメソッドの静的な事前定義の他、実行時にも動的にデータとメソッドを付け替えできる。プロトタイプないしクラスもプログラマが自由に扱えるオブジェクトになっている。
'''[[オブジェクト (プログラミング)|オブジェクト]]''' ({{Lang|en|object}}) はオブジェクト指向プログラミングの中心となる'''概念'''であり、この概念を'''実際'''にどう実現するかは[[オブジェクト指向プログラミング言語]]により異なる。
;[[リフレクション (情報工学)|リフレクション]]
:(''reflection'')は、メタクラス内容を閲覧/変更する機能であるが、変更できる内容範囲は言語ごとに異なっている。データではデータ型、識別子、可視性が変更対象になる。メソッドではリターン型、識別子、パラメータリスト、可視性、オーバーライド指定が変更対象になる。双方の追加定義と削除もできる事がある。スーパークラスも変更できる事がある。メタクラスの変更はそのまま関連クラスと関連インスタンスにリフレクション(反映)される。ただし反映範囲はこれも言語によって異なる。
:また、実行時の文字列(char配列やString)をデータとメソッドの内部識別子として解釈できる機能もリフレクションであり、上述のメタクラス操作よりもこちらの方がよく用いられる。これは実行時の文字列データを用いてのデータ/メソッドへの動的なアクセスを可能にする。
;[[アノテーション|メタアノテーション]]
:(''metadata annotation'')はクラスに任意の情報を埋め込める機能である。情報とは文字列と数値からなるキーワード、シンボル、テキストである。プログラマが自由な形式で書き込んで随時読み取るものであるが、システムから認識される形式のものもある。実装レベルではメタクラスに書き込まれてリフレクション機能またはその[[糖衣構文]]で読み取ることになる。[[マーカーインタフェース|マーカーインターフェース]]の拡張とも見なされている。メタアノテーションはクラス単位だけでなく、言語によってはインスタンス単位やメソッド単位でも埋め込むことができる。
;メソッド拡張
:(''method extension'')は、クラス定義とは別の場所でそのクラスに対する追加メソッドを定義できる機能である。これは状況に合わせてデータ抽象の表現に幅を持たせることを目的にしている。これには数々の書式があるが代表的なのは、静的メソッドまたは静的関数の第1引数をthis修飾して、その第1引数のクラス(型)に対してその静的メソッドをインスタンスメソッドとして追加するというものである。静的メソッドはそのクラススコープ内の限定拡張にできる。静的関数はネスト関数にしてそのローカルスコープ内の限定拡張にできる。双方はグローバル用途にすることもできる。


;動的ディスパッチ
以下、概念と実際がどう対応しているかについて説明する。
:(''dynamic dispatch'')は、コンパイル時のメソッド名から呼び出されるメソッド内容が実行時に決定される仕組み全般を指す用語である。メソッドに引数を渡しての呼び出しを、オブジェクトにメッセージを発送(ディスパッチ)することになぞらえた事が由来である。発送先は実行時に選択決定されるメソッド内容を指す。メッセージは「[[This (プログラミング)|this参照]]×第1引数×第2引数..」といった[[直積集合]]で考えられているのでシングル、ダブル、マルチプルといった呼称になっている。発送先はthisおよび各引数の派生関係の組み合わせで選択される。thisの派生関係のみ影響しているものは仮想関数と呼ばれるシングルディスパッチになる。それがthisでなく引数ならばただのシングルディスパッチになる。thisまたは各引数の内の2個以上のオブジェクトの派生関係が影響しているものは[[多重ディスパッチ|マルチプルディスパッチ]]になる。その中で特にthisと先頭引数の2個が影響して先頭引数インスタンスの仮想関数がthisを引数にしているVisitor形態のものは[[ダブルディスパッチ]]と呼ばれている。
;[[動的束縛|動的バインディング]]
:(''dynamic binding'')は、識別子が参照するまたは呼び出すオブジェクト、インスタンス、メソッド、データなどのプログラム要素が、コンパイル時ではなく実行時に決められる仕組み全般を指す用語である。識別子はいわゆる変数名や関数名などを指す。


;遅延バインディング
* 概念的には各々のオブジェクトは、プログラムが表現する情報システムの中で能動的な役割を持った存在を表現している。
:(''late binding'')は、識別子が参照するオブジェクトをコンパイル時に決める事前バインディング(''early binding'')の対義語であり、この場合は識別子が参照するオブジェクトを実行時に決める動的バインディングと同じ意味で用いられる。また他方では動的バインディングの中で、特に実行コードの動的ローディング機能を通して実装される方を遅延バインディングとする考え方もある。実行コードとは[[ダイナミックリンクライブラリ|DLL]]やクラスライブラリやモジュールなどを指しており、それらが内包するクラスやメソッドを専用の不透明型または動的束縛型に代入する。その呼び出しのための内部識別子はコンパイル時には存在していないことが多いので、実行時の文字列(char配列やString)を内部識別子に解釈するためのリフレクション機能が多用されることになる。
* 概念的には '''メッセージ'''を受け取り、その処理の過程で内部に蓄えたデータを書き換え、必要に応じて他のオブジェクトにメッセージを送るといった動作をしている。
* 概念的には コードとデータが一つになっている。


;[[パッケージ (Java)|パッケージ]]
==== オブジェクトの実装構造 ====
:(''package'')は1個以上のクラスをまとめたものである。多くなったクラスをグループ化するための仕組みである。パッケージの定義は言語ごとに異なるが、[[名前空間]](''namespace'')と同等の機能になっているケースが多い。実装レベルではパッケージ名は自動的にクラス名の接頭辞になってクラス名を差別化し、名前衝突を回避している。
実際のプログラムでは、全てのオブジェクトが互いに全く異なった存在ではなくオブジェクトは種類に分けることが出来る。


;[[モジュール]]
例えば勤怠管理のシステムであれば、氏名や年齢、累積勤務時間などの'''データ'''は異なっても社員は皆、出勤し退勤するという処理('''振る舞い''')は同じだろう。このように複数の異なるオブジェクトが同じ種類のメッセージを受け取り共通の処理をするのが普通である。
:(''module'')は1個以上のクラスをまとめたものである。ここでは[[手続き型プログラミング|手続き型]]や[[構造化プログラミング]]でのそれではなく、OOP言語で扱われているモジュール概念について説明する。ただしその定義は言語間で様々である。上述のパッケージと同等の機能にしている言語もある。ミックスインのために使われる変数と関数のメンバグループをそれにしてトレイトと同等の機能にしている言語もある。また、クラス群の動的ローディングに焦点を当てた[[ソフトウェアコンポーネント]]相当の機能にしている言語もある。この動的ローディングは遅延バインディングと同義になり、実行中プロセスへのクラス群の逐次追加を可能にしている。動的ローディング用途のモジュールでは、内包する基底クラスの詳細を明らかにしつつも、その派生クラスの種類と詳細を明らかにしていないケースが多々あるので、その派生クラスを代入するための動的束縛型は特に不透明型(''opaque type'')と呼ばれる。不透明型はもっぱら型制約と併せて用いられる。
;[[モンキーパッチ]]
:(''monkey patch'')はモジュールやスクリプトファイルなどの動的ローディングを用いて、インタプリタ実行後またはコンパイル後のソースコード内容を変化させる手法である。ソースコードに専用のフィルター処理を記述しておき、その中で任意の箇所を動的ローディングされたモジュール内のクラスや関数や変数で置き換えさせる事で、その時の配置モジュールに合わせた処理内容の変化を起こせる。モジュールを外せば専用のフィルター処理は無効になる。この置き換え(パッチ当て)は遅延バインディング相当である。ソースコードを変えなくてよいのが条件である。
;[[ジェネリクス]]
:(''generics'')は、クラスメンバの任意の「型」を総称化したままのクラス定義を可能にし、そのクラスをインスタンス化する各構文箇所で「型」の詳細を決定できるようにしたコンパイル時の静的な機能である。言語によっては[[テンプレート (プログラミング)|テンプレート]](''template'')と呼ばれる。ここでの「型」とはデータの型やメソッドの引数値/返り値/計算値の型を指している。クラス内のそれらを総称化して型変数にし、コンストラクタ呼び出し時の仮型引数に実型引数を適用すると、型変数に実型引数を当てはめたインスタンスが生成される。総称化された型を持つクラスはジェネリッククラスと呼ばれる。特定の型に依存しないクラスを汎用的に定義できるので、型が違うだけの重複コードを削減できるという利点がある。
:言語によっては、ジェネリッククラス同士を[[共変性と反変性 (計算機科学)|共変性と反変性]]による継承関係で結ぶことができる。これはジェネリッククラスに適用する実型引数の継承関係を、そのジェネリッククラス同士の継承関係にシフトする仕組みである。<code>class 猫 extends 動物</code>とすると<code>List<猫></code>は<code>List<動物></code>のサブクラスになる。共変性は実型引数の継承関係をそのままジェネリッククラスの継承関係にシフトするが、反変性ではこれを逆にする。共変性では<code>List<猫></code>は<code>List<動物></code>のサブクラスだが、反変性では<code>List<動物></code>は<code>List<猫></code>のサブクラスになる。[[共変性と反変性 (計算機科学)|共変性と反変性]]はまとめてバリアンス(''variance'')と呼ばれる事がある。
;型制約
:(''type constraint'')は、(A)ジェネリッククラスの型引数/型変数、(B)代入値の型が実行時に決められる動的束縛型の変数、(C)動的ローディング時に詳細が隠されたままの値が代入される不透明型の変数、などの宣言に用いられるものである。それぞれは制約用の基準クラスで記号修飾され、その基準クラス及びその派生型の値が代入、束縛、適用されるという宣言になる。(A)の型引数/型変数では基準クラス及びその派生クラスが適用される宣言になる。(B)の動的束縛型では基準クラス及びその派生型の値が代入される宣言になる。(C)の不透明型では基準クラス及びその詳細不明である派生型の値が代入される宣言になる。型制約は型境界(''type bound'')とも呼ばれる。これには上限と下限がある。型制約と上限型境界(''upper type bound'')は性質的に同義である。下限型境界(''lower type bound'')は、基準クラス及びその基底型の値が代入、束縛、適用されるという宣言になる。
;タイプメンバ
:(''abstract type member'')はジェネリッククラスのメンバ要素であり、ジェネリッククラス同士で型変数の内容をやり取りするための仲介要素である。Aクラスコンストラクタの型引数にBクラスを適用した際に、適切な代入定義が併記されたAクラス内のタイプメンバに、Bクラスがその内部で扱っている総称型もセットで適用できる。連想配列さながらにBクラスがキー的存在になってAクラスのタイプメンバ内容も決定されることから、この仕組みは関連型または連想型(''associated type'')と呼ばれる。
;[[関数オブジェクト]]
:(''function object'')はクラスベースでは、( )[[演算子オーバーロード]]による実装と、[[デリゲート (プログラミング)|デリゲート]]による実装などがある。前者はインスタンスを単に関数名らしく見せるための糖衣構文である。後者のデリゲートは、メソッドシグネチャを型種にした[[関数ポインタ]]型の変数である。デリゲート変数にはインスタンスメソッドへの参照が代入されてそのインスタンス種類による処理の多相を表現できる。プロトタイプベースでは、関数はそのままプロパティ/メソッドを自由に付け替えできる(動的バインディング)オブジェクトになる。それらは同時に関数のローカル変数/関数になる。
;[[コルーチン]]
:オブジェクト指向下の[[イテレータ]]と[[ジェネレータ (プログラミング)|ジェネレータ]]は、コルーチン(''coroutine'')機構に基づいている。通常のサブルーチンがコールする側の復帰アドレスだけをスタックに積むのに対して、コルーチンはコールする側とコールされる側双方の復帰アドレスをスタックに積むというサブルーチン機構である。各要素への作用が記されたオペレータが[[無名関数]]やラムダ式などの形態で[[コンテナ (データ型)|データコンテナ]]に渡されると、各要素をフェッチするデータコンテナと、フェッチされた要素を参照ないし加工するオペレータが交互に[[コールスタック]]を用いて連携動作を繰り返す。イテレータはデータコンテナの各要素にオペレータを適用してその結果値に置き換えていく機能である。ジェネレータは(A)データコンテナを複製してその複製先の各要素にオペレータを適用していくという更新コンテナ生成機能、(B)オペレータがデータコンテナの各要素を選別していき最後に全選別要素を結合したコンテナを生成する機能、(C)オペレータがデータコンテナを走査して各要素の総和値を生成する機能の三種がある。
;[[メッセージ転送|メッセージレシーバー]]
:(''message receiver'')は、メソッド名を文字列で受け取ることができる仕組みであり、インスタンスのデフォルトメソッド(共通窓口メソッド)として備えられるものである。メソッド名の次に引数が渡される。メソッド名文字列はセレクタとも呼ばれる。プログラマはセレクタをレシーバー内で自由に解釈して任意のプロセスに選択分岐できる。通常の<code>instance.method(arg)</code>が、レシーバー機構では<code>instance selector: arg</code>や<code>instance.receiver(method_name, arg)</code>のようになる。受け取ったセレクタによる選択分岐をシステム側が自動化したものがメソッドになった。これの応用形であるメソッドミッシングは、インスタンスに事前定義されていないメソッドが呼び出された時にのみ、取りこぼし用のレシーバーが呼び出されて、文字列化されたメソッド名と引数が渡されるという仕組みである。
;[[イミュータブル|イミュータブル・オブジェクト]]
:(''immutable object'')は、データ不変設定されたクラスのインスタンスを意味する。定数だけを持つインスタンス、不変文字列、不変プリミティブの[[ボックス化|ボックス型]]、収納内容が不変のコレクション(Array、List、Set、Map)などを指す。イミュータブル(不変)はオブジェクトの性質というよりも、それを何のためにどう扱うかというアルゴリズムとデザインパターンの方が要点になる。不変オブジェクトは[[並行計算|並行OOP]]と[[関数型言語|関数型OOP]]で最も重要視される。不変オブジェクトではセッターとミューテイタは禁止され、代わりに元への変更を反映して新たに生成したオブジェクトが返されることになる。コレクションクラスでは要素の追加/削除/変更による結果内容のコレクションが新たに生成されてそれが返り値にされまた引数用途にもなることから、これはファーストクラスコレクションと呼ばれる。なお、不変オブジェクトをコピーした専用の可変オブジェクトを取得したのならば、それへのセッターとミューテイタは許される。これは''copy-on-write''と呼ばれる。


;[[委譲|デリゲーション]]
このような場合、各オブジェクトがそれぞれメッセージ処理のコード(前述の「振る舞い」に当たる)を独自に備えていては無駄である。そこでオブジェクト指向プログラミング言語がオブジェクトを実現する際には多くの場合、内部的にはオブジェクトを2つの部分に分けている。
:委譲(''delegation'')。呼び出されたあるクラスのメソッドが自分への引数を他のクラスの同名メソッドにそのまま渡して、その同名メソッドからの返り値をそのまま呼び出し元に渡すという仕組みを指す。委譲先のクラスはhas-a関係で保有されているものになる。委譲先メソッドは必ずしも同名ではなくマッピング名の場合もあり、引数も構成を変えて渡される場合もある。
;フォワーディング
:転送(''forwarding'')。委譲先のクラスのメソッドが処理を行わずに、そのまた他のクラスの同名メソッドに引数をそのまま渡して、その返り値をそのまま呼び出し元に渡している場合、冒頭の委譲は転送になる。転送用メソッドではどのクラスに引数をパスするかという選択が行われるので、デリゲーションの多相を表現できる。


;[[派生型|サブタイピング]]
; 同一種類のオブジェクトの間で変わらない共通部分
:(''subtyping'')はクラス(型)のあらゆる派生関係および派生構造の実装形式とその働き方を包括したプログラム概念である。サブタイプ多相(''subtype polymorphism'')とも呼ばれる。継承、オーバーライド、コンポジション、ジェネリクス、共変反変バリアンス、不透明型といったものは全てサブタイピングの一側面である。オブジェクト指向でよく使われるものは、振る舞いサブタイピング(''behavioral subtyping'')であり、継承とメソッドオーバーライドの合わせ技である仮想関数がそれに当たる。
: 一つは同一種類のオブジェクトに共有される部分、例えばメッセージ処理のコード(振る舞い)や定数(どのオブジェクトでも異ならないデータ)の類である。
; 同一種類のオブジェクトの間で変わる個々の部分
: もう一つは同一種類のオブジェクトでもそれぞれ異なる部分、典型的には各オブジェクトが保持するデータ群である。


;[[Is-a|Is-a関係]]
==== クラスのオブジェクト化 ====
:(''Is-a'')は[[上位概念、下位概念、同位概念および同一概念|上位概念と下位概念]]のコンセプトを扱っており、下位概念is-a上位概念となる。オブジェクト指向ではクラスの継承関係および実装継承関係を意味する用語になっている。これには汎化・特化・実現・実装の四種がある。
動的型付けを採用するオブジェクト指向言語の多くは、クラスより生成するインスタンスの他に[[メタクラス]]という機能を持ちクラス自体をオブジェクトとして扱うことが出来る。このためオブジェクトには、インスタンスオブジェクトとクラスオブジェクトという2種類のオブジェクトが存在する。Java等クラスオブジェクトを持たない言語の文化圏では、インスタンスオブジェクトとオブジェクトを混同して説明される事があるが、Objective-CやPython、Ruby等、インスタンスオブジェクトとクラスオブジェクトが別であるオブジェクト指向言語では区別して説明される。<ref>Objective-Cプログラミ
:* 汎化(''generalization'')は、サブクラスからスーパークラスへの連結を指す。
ング言語[https://developer.apple.com/jp/devcenter/ios/library/documentation/ObjC.pdf]</ref>
:* 特化(''specialization'')は、スーパークラスからサブクラスへの連結を指す。
<ref>Classes ― Python v2.7.3 documentation[http://docs.python.org/2/tutorial/classes.html]</ref>
:* 実現(''realization'')は、クラスからインターフェースへの連結を指す。
<ref>クラス/メソッドの定義 (Ruby manual) [http://www.ruby-lang.org/ja/old-man/html/_A5AFA5E9A5B9A1BFA5E1A5BDA5C3A5C9A4CEC4EAB5C1.html]</ref>元々はSmalltalkから始まった用語である。
:* 実装(''implementation'')は、インターフェースからクラスへの連結を指す。
;[[Has-a|Has-a関係]]
:(''Has-a'')は[[部分集合|上位集合と部分集合]]のコンセプトを扱っており、上位集合has-a部分集合となる。オブジェクト指向ではクラスの構成関係を意味する用語になっている。これには合成・集約・収容・依存の四種がある。なお、依存(''dependency'')はhas-a関係における依存とそれ以外のクラス間関係における依存の意味が異なる二つが存在する。
:* 合成(''composition'')は強いhas-a関係であり、AクラスがBクラスをデータにし、Aクラスのコンストラクタと同時にBインスタンスが生成され、Aクラスのデストラクタと同時にBインスタンスが破棄される場合、AはBの合成となる。Bが自身のサブクラスで交換される場合は分離とともに破棄される。
:* 集約(''aggregation'')は弱いhas-a関係であり、AクラスがBクラスをデータにし、Aクラスのコンストラクタとは関係なくBインスタンスが生成され、AクラスのデストラクタでBインスタンスが破棄されず、また分離時も破棄されない場合、AはBの集約となる。Aクラスがコレクション(配列、List、Set、Map)の仕組みでBインスタンスを持つ場合も、AはBの集約となる。
:* 収容(''containment'')は弱いhas-a関係であり、集約と同じであるが、Aクラスがコレクション(配列、List、Set、Map)の仕組みでBインスタンスを持つ場合のみを指している。コレクション関係を強調する場合、AはBを収容しているとなる。
:* 依存(''dependency'')は強いhas-a関係であり、Aクラスのいずれかのメソッドが、Bクラスを引数の型または返り値の型にしている場合、AはBに依存しているとなる。なお、AクラスがBクラスの型のデータを[[has-a]]している場合のAからBへの依存は、合成/集約の方で省略されている。


;[[SOLID|SOLID原則]]
==== thisデータの扱い方 ====
:(''SOLID Principles'')は、いわゆる抽象化に焦点を当てたクラスの設計原則である。(S)単一責任原則・(O)解放閉鎖原則・(L)リスコフの置換原則・(I)インターフェース分離原則・(D)依存性逆転原則といった五つから成り立っている。1988年に[[バートランド・メイヤー]]が提唱した(O)と、1994年に[[バーバラ・リスコフ]]が提示した(L)に、ソフトウェア技術者ロバート・マーティンが(S)(I)(D)を加えて2000年に発表されている。
{{seealso|this (プログラミング)}}
:* (S){{仮リンク|単一責任原則|en|Single-responsibility principle}}は、クラスをただ一つの機能を表現するようにデザインすることを推奨している。
そしてあるオブジェクトOにメッセージを配送し適切なメッセージ処理コード(振る舞い)を呼び出す際には、まず対象となるオブジェクトOについて共通部分の格納場所を見つけて適切なコードを選び出し、次にそのコードに対して処理対象となるオブジェクトO固有のデータの所在を示す'''オブジェクトID'''を渡すようになっている。
:* (O)[[開放/閉鎖原則|解放閉鎖原則]]は、クラスを抽象クラスと実装クラスに分けてデザインすることを推奨している。抽象クラスの定義内容は変更に閉じられており、実装クラスの処理内容は拡張に開かれていることが由来である。
:* (L)[[リスコフの置換原則]]は、実装クラスはその抽象クラスに対して振る舞い的に等価計算が可能であることを推奨している。抽象側の公開保有メソッドを実装側も全て保有していれば等価となる。ここでの置換(''substitution'')とは抽象クラスの型の変数に実装クラスの型のインスタンスを代入できることを意味している。
:* (I){{仮リンク|インターフェース分離原則|en|Interface segregation principle|label=}}は、一つのクラスから実現される抽象クラスを一つに限定せず、互いに処理内容に影響し合うメソッド群ごとに分離して複数実現することを推奨している。
:* (D)[[依存性逆転の原則|依存性逆転原則]]は、AクラスがBクラスの機能を使用したい場合は、まずBからその抽象クラスをAに向けて実現し、Aはその抽象クラスを通してBの機能を使用することを推奨している。AはBの機能を使用するという意味でその抽象クラスに依存し、Bは自身の機能を提供するという意味でその抽象クラスに依存することになる。ここでの逆転(''inversion'')とは実装から抽象への方向性を意味している。


; [[デザインパターン (ソフトウェア)|GOFデザインパターン]]
各オブジェクトの固有データを識別するオブジェクトIDを表現する方法も様々で、オブジェクトのIDとしては名前、番号なども用いられることがあるが、オブジェクトの固有データを記憶している[[主記憶]]上の[[メモリアドレス|アドレス]]がそのまま用いられることもある。アドレスを直接利用することは非常に実行効率の向上に寄与するが、プログラム間でのオブジェクトの受け渡し、セッション間(プログラムが終了して再度起動された時など)でのオブジェクトの受け渡しにはそのまま利用することができない。
: (''Gang of Four Design Patterns'')はソフトウェア開発において直面しやすい共通的かつ代表的なデザイン問題をピックアップし、それぞれの解決に最適なクラスパターン図を提示したものである。1994年から四人の計算機科学者ないしソフトウェア技術者たち([[Gang of Four]])によって発表され、OOPのデザインパターンの代表格と見なされた。教科書の内容としても取り上げやすい形式化されたトピックであったためにオブジェクト指向の学習面では非常に重視された。5個の生成パターン、7個の構造パターン、11個の振る舞いパターンに分類されている。

: 生成に関するパターン<gallery heights="40">
また各オブジェクトの固有データから共通部分の格納場所を見つける方法もまた各言語により異なり、その言語の開発目的に応じて実に多種多様である。
ファイル:Abstract Factory UML class diagram.svg|[[Abstract Factory パターン|Abstract factory]]

ファイル:Builder UML class diagram.svg|[[Builder パターン|Builder]]
; JavaScriptの場合
ファイル:Factory Method UML class diagram.svg|[[Factory Method パターン|Factory Method]]
: 例えば[[JavaScript]]の場合、各オブジェクトは[[連想配列]]であり、名前で表現されたメッセージのIDからメッセージ処理コードである関数への参照を直接見つけ出す。各オブジェクトの固有データもその連想配列に格納されていて、メッセージを処理する関数には連想配列のアドレスが渡される。
ファイル:Prototype UML.svg|[[Prototype パターン|Prototype]]
; Selfの場合
ファイル:Singleton UML class diagram.svg|[[Singleton パターン|Singleton]]
: [[Self]]のような[[プロトタイプベース|インスタンスベース]]のオブジェクト指向プログラミング言語では、プロトタイプとなるオブジェクトがメッセージを処理するコードも保持しており、オブジェクトがクローンされて作成されるときにそのプロトタイプのありかを示す情報もコピーされ、メッセージは受け取ったオブジェクトのIDを添えてプロトタイプに送られて処理される(Selfでは実行効率上の問題から後に内部的にクラスを作って利用するようになっている)。
</gallery>
; クラスベースの言語の場合
: 構造に関するパターン<gallery heights="40">
: 最も普及している[[クラスベース]]の言語では、共通部分はオブジェクトの種類を表現するクラスに保持され、各オブジェクトは固有データと共にそのクラスのIDを保持する。そしてオブジェクトに送られるメッセージはその送り先オブジェクトにあるクラスのIDからクラスを見つけ、その中からメッセージを処理するコードを見つけ出し、処理対象となっているオブジェクトのIDを付してそのコードを呼び出す仕組みになっている。
ファイル:Adapter pattern UML diagram.PNG|[[Adapter パターン|Adapter]]

ファイル:Bridge UML class diagram.svg|[[Bridge パターン|Bridge]]
==== コンポジション ====
ファイル:Composite UML class diagram (fixed).svg|[[Composite パターン|Composite]]
'''コンポジション'''は、複数のオブジェクトがある一つのオブジェクトの構成要素となっている巨大なオブジェクト群をいう。コンポジションのもとにあるオブジェクトは同一の生存期間を持ち、一つの巨大な仮想オブジェクトの構成部品として機能する。
ファイル:Decorator UML class diagram.svg|[[Decorator パターン|Decorator]]

ファイル:Facade UML class diagram.svg|[[Facade パターン|Facade]]
=== メッセージ ===
ファイル:Flyweight UML class diagram.svg|[[Flyweight パターン|Flyweight]]
'''メッセージ''' ({{Lang|en|message}}) はオブジェクト間の通信でやりとりされる情報である。メッセージはメッセージ種別を示すIDとメッセージの種別に応じた追加の情報からなる定まった形式を持つ。追加の情報はそれ自身が何らかのオブジェクトや[[オブジェクトのID]]である場合もある。メッセージの配送には大別して2つの方式がある:
ファイル:UML DP Proxy.png|[[Proxy パターン|Proxy]]

</gallery>
; 同期式
: 振る舞いに関するパターン<gallery heights="40" perrow="11">
: オブジェクトがメッセージの送信を依頼すると相手が受信、処理して結果を返すまでそのオブジェクトは処理を中断して待つ。
ファイル:Chain of responsibility UML diagram.png|[[Chain of Responsibility パターン|Chain of Responsibility]]
; 非同期式
ファイル:Command Design Pattern Class Diagram.png|[[Command パターン|Command]]
: オブジェクトがメッセージの送信を依頼した後、相手の応答を待たずにオブジェクトは処理を続行する。処理結果は別のメッセージとして返される。
ファイル:InterpreterUMLDiagramm.png|[[Interpreter パターン|Interpreter]]

ファイル:Iterator UML class diagram.svg|[[Iterator パターン|Iterator]]
両者とも一長一短がありどちらがすぐれているとは言えない。また並列・並行処理が可能な環境では一方の仕組みがあれば、それを利用してもう一方も実現可能である。一般的な傾向としては、メッセージの伝送や処理に時間が掛かる場合は非同期式の方が効率は良く、そうでない場合には同期式の方が挙動が分かりやすく利用しやすい。
ファイル:Mediator design pattern.png|[[Mediator パターン|Mediator]]

ファイル:Memento design pattern.png|[[Memento パターン|Memento]]
[[並列処理]]・[[並行処理]]システムを記述する言語や[[分散コンピューティング|分散システム]]を記述する言語ではOSなどが提供するメッセージ機能や自前の配送メカニズムを使って非同期式でメッセージが配送される場合もあるが、一般にオブジェクト指向プログラミング言語ではその多くが同一のプログラム内の通信であるので同期式のメッセージ配送が利用される。特に[[コンパイル]]されるタイプのオブジェクト指向プログラミング言語では、しばしば特別なメッセージ配送の仕組みを用意せず、特別な形式の関数の呼び出しでメッセージの配送を直接に表現する。即ち、各メソッドを内部的には関数として実現し、メッセージIDはメソッド名で表し、関数の第一引数としてオブジェクトIDを渡し(この第一引数は多くの言語で特別な記法で表される)、追加の引数としてメッセージの追加部分の情報を渡すのである。こうするとメッセージ送信は直接的なメソッドの関数呼び出しとして表せる。ただし、プログラムで[[継承 (プログラミング)|継承]]の仕組みが利用されている場合はプログラムのテキストからだけでは呼び出すべきメソッドが決定できない場合があるので、実行時にメソッドを決定するために[[メソッド・サーチ]]や[[仮想関数テーブル]]といった仕組みが必要となる。
ファイル:Observer UML smal.png|[[Observer パターン|Observer]]

ファイル:State Design Pattern UML Class Diagram.svg|[[State パターン|State]]
多くのプログラミング言語においてメッセージは、メソッド呼び出しの比喩でしかないことが多い。SmalltalkやObjective-Cの様な言語では、メッセージはメソッド呼び出しとは独立した機構として存在している。メッセージが機構として存在する言語では、メッセージをオブジェクトに送信した際、宛先のオブジェクトにメッセージで指定したメソッドが存在しない場合でもメッセージを処理することが出来る。これを利用し、メッセージの配送先を別のオブジェクトに指定したり、メッセージを一時保存したり、不要なメッセージを無視する等といったメッセージ処理が行われる。
ファイル:Strategy Pattern in UML.png|[[Strategy パターン|Strategy]]

ファイル:Template Method UML class diagram.svg|[[Template Method パターン|Template Method]]
{{seealso|メッセージ転送}}
ファイル:Visitor UML class diagram.svg|[[Visitor パターン|Visitor]]

</gallery>
=== クラス ===
{{main|クラス (コンピュータ)}}
==== クラスベース ====
'''クラス''' (class) は大多数のオブジェクト指向プログラミング言語で提供されている仕組みであり、上記の機能のほとんど全てに関わりがある。概念的にはクラスはオブジェクトの種類を表す。このためオブジェクトはクラスに'''属する'''という言い方をする。あるクラスに属するオブジェクトのことをそのクラスの'''インスタンス''' (instance) と呼ぶ。[[データ型]]の理論から見た場合クラスは型を定義する手段の一つである。クラスによってオブジェクトを記述する言語を'''[[クラスベース]]''' ({{Lang|en|class-based}}) のオブジェクト指向プログラミング言語と呼ぶ。

ハイブリッド型オブジェクト指向プログラミング言語では在来の[[データ型#レコード型|レコード型]](Cでは[[構造体]])の構文を拡張してクラスの定義を行うようにしたものが多い。

多くのオブジェクト指向プログラミング言語ではクラスを'''[[#データ・メンバ|データメンバ]]'''と'''[[#メソッド|メソッド]]'''の集まりとして記述する。平たく言えばデータ・メンバの集まりはオブジェクトが保持するデータの形式を定め、各メソッドはそれぞれオブジェクトが処理する特定のメッセージの処理方法を定める。しばしばデータ・メンバとメソッドには個別に[[オブジェクト指向プログラミング#アクセス権|アクセス権]]が設定できるようになっていて、そのクラスに属するオブジェクトが内部的に利用するものと他のクラスに属するオブジェクトに公開するものを分類できるようになっている。多くの場合、公開されたメソッドの集まりは全体として処理可能なメッセージのカタログの機能、即ち[[インタフェース (情報技術)|インタフェース]]を提供する。各言語によって異なるが特定の名前のメソッドを定めて、オブジェクトの生成や初期化時の処理、廃棄時の処理などを記述できるようにすることも多い。

多くの言語でクラスは言語の要素として直接実現されているが、これは実行効率のためであり、そのように実現することが必須というわけではない。実際、各クラスをそれぞれオブジェクトとして提供する言語も存在する(例:[[Smalltalk]])。このような言語ではある種の'''[[リフレクション (情報工学)|リフレクション]]''' (reflection) が可能となる。即ち必要があればプログラムで実行時にクラスの動作を変更することが可能である。これは非常に大きな柔軟性を提供するが、[[処理系|言語処理系]]による最適化が難しいため実行効率は低下することが多い。{{いつ範囲|date=2019年2月|近年}}では柔軟性と効率性を両立させるために基本的に言語要素としてクラスを提供した上で、リフレクション機能が必要なプログラムに対しては必要に応じて各クラスに対応するクラス・オブジェクトをプログラムが獲得できるようにしている言語が現れてきている。(例:JavaのリフレクションAPI)

==== プロトタイプベース ====
{{main|プロトタイプベース}}
クラスは非常に多くのオブジェクト指向プログラミング言語で提供されている機能ではあるが、オブジェクト指向プログラミング言語に必須の機能というわけではない。実際にオブジェクトの管理や、データ・メンバや[[メソッド (計算機科学)|メソッド]]の記述、[[継承 (プログラミング)|継承]]に際してクラスという仕組みに依存せずに、もしくはクラスという仕組み自体を持たずに別の手段でこれらを実現している言語も存在する。このような言語を'''[[プロトタイプベース|インスタンスベース]]''' (''{{Lang|en|instance-based}}'')、'''オブジェクトベース''' (''object-based'') あるいは'''プロトタイプベース''' (''{{Lang|en|prototype-based}}'') のオブジェクト指向プログラミング言語と呼ぶ。インスタンスベースまたはそれに類するオブジェクト指向プログラミング言語には以下のようなものがある:

*[[Self]]
*[[JavaScript]]
*[[NewtonScript]]
*[[ドリトル (プログラミング言語)|ドリトル]]
* Squeak [[Etoys|eToys]]([[Squeak]]の非開発者向けビジュアルスクリプト言語。SqueakToys とも)

なお、クラスベースの言語とインスタンス・ベースの言語との間には明確な境界線はない。たとえば、インスタンス・ベースの代表格ともいえる Self には、traits と呼ばれるクラスのような仕組みが追加されているし、JavaScript、NewtonScript に至っては traits 類似の仕組みを「クラス」と呼称している。また逆に、クラスベースの言語でもクローンを行うメソッドを備え、委譲の仕組みを記述すればある程度はインスタンス・ベースのスタイルでプログラムを記述できる。

インスタンス・ベースの言語ではオブジェクトの生成は既存のオブジェクト、特に'''プロトタイプ'''({{Lang|en|prototype}}、原型)と呼ばれるオブジェクトからのクローンによって行われる。当然、一群のクローンはその親、ひいてはプロトタイプと同一の種類のオブジェクトと見なされる。メソッドはプロトタイプ・オブジェクトに属し、メッセージは委譲によってそのオブジェクトが覚えているコピー元へ向かってプロトタイプまで順にメッセージが中継されてから処理される。新しい種類のオブジェクトが必要な場合は適当なオブジェクトをクローンした後で必要なデータ・メンバやメソッドを追加あるいは削除し新たなプロトタイプとすることで行われる。追加されたのでないメソッドに対応するメッセージについてはコピー元のオブジェクトに処理を委譲する。

クラスベースの言語との関係について考えてみると、クローンはプロトタイプと同一の「クラス」に属すると見なし、データ・メンバやメソッドが追加・削除されてあらたなプロトタイプが作られると別の「クラス」が内部的に生成されると考えることができる。ここでデータ・メンバやメソッドの追加のみを許して削除を許さないよう制限すればクローンの「クラス」がその親の「クラス」を継承した場合と同等になる。このためメッセージが委譲の連鎖をたどって配送されるという効率上の問題を無視すれば理論上、インスタンス・ベースの言語の記述能力はクラス・ベースの言語を包含していると言える。ただ、インスタンス・ベースの言語でも実行効率上の問題からなんらかのクラスに似た仕組みを備えている場合が多い。

=== データメンバ ===
'''データメンバ''' ({{Lang|en|data member}}) は、他のオブジェクトに対する[[参照 (情報工学)|参照]]や[[ポインタ (プログラミング)|ポインタ]]であるか、他のオブジェクトそのものである。参照かポインタである場合にはそのデータメンバの参照するのはデータメンバが記述されているクラスそのもののインスタンスに対する参照であっても良い。

一般にデータメンバは'''インスタンスデータメンバ'''('''[[インスタンス変数|インスタンスフィールド]]''')と'''クラスデータメンバ'''('''静的変数''')の2種類に大別できる。効率上の観点から言語が提供する基本オブジェクトの定数を表すデータメンバは特別扱いされる。そのような定数を表すデータメンバを特に'''定数データメンバ''' ({{Lang|en|constant data member}}) と呼ぶ。データメンバは[[C++]]などの言語では'''メンバ変数''' ({{Lang|en|member variable}})、[[Java]]などでは'''フィールド'''と呼ばれることがあり、[[統一モデリング言語|UML]]では[[属性]]と呼ばれる。

==== インスタンスデータメンバ ====
{{main|インスタンス変数}}
インスタンスデータメンバ(一般に単にデータメンバと言われる場合はこちら)はそのクラスのインスタンス各々に保持される。インスタンスデータメンバの集まりはそのクラスのインスタンスが保持するデータの形式を定める。インスタンスデータメンバは単にデータメンバと呼ばれることも多い。

[[Smalltalk]]では'''[[インスタンス変数]]''' ({{Lang|en|instance variable}}) と呼ばれる。

==== クラスデータメンバ ====
{{main|クラス変数}}
クラスデータメンバはそのクラスオブジェクトとインスタンスオブジェクトの間で共有されるデータである。

[[Smalltalk]]ではクラスデータメンバは'''[[クラス変数]]''' ({{Lang|en|class variable}}) と呼ばれる。また、[[C++]]・[[Java]]では歴史的事情によりクラスデータメンバは'''静的データメンバ''' ({{Lang|en|static data member}})、'''静的変数''' (static variable)、'''静的フィールド''' ({{Lang|en|static field}}) と呼ばれる。

ただし、Smalltalkのクラス変数はC++やJavaのクラス変数とは異なる。Smalltalkにおいて、C++やJavaのクラス変数と同等となる変数は'''プール辞書''' ({{Lang|en|pool dictionary}}) と呼ばれる。

=== メソッド ===
'''[[メソッド (計算機科学)|メソッド]]''' ({{Lang|en|method}}) は特定の種類のメッセージの処理方法を記述したものである。メソッドも[[メソッド (計算機科学)#インスタンスメソッド|インスタンス・メソッド]]と[[メソッド (計算機科学)#静的メソッド|クラス・メソッド]]の2種にできる。インスタンス・メソッドはそのクラスの各インスタンスオブジェクトを操作し、クラス・メソッドはクラスオブジェクトを操作する。メソッドとの集まりはそのクラスのオブジェクトが処理可能なメッセージのカタログの機能を果たす。

一例として、[[C++]]では、メソッドは'''メンバ関数''' ({{Lang|en|member function}}) や'''関数メンバ''' (function member) と呼ばれる。これはC++が[[グローバル関数]]との区別をつけることと、クラスを[[抽象データ型]]の拡張と位置づけ、非メッセージメタファな言語思想を持っているためである。これら言語ではメソッドをオブジェクト(=クラスやインスタンス)の持ち物として捉えず、クラスに定義された機能要素であると考える。メッセージメタファを否定するため、同時にメッセージを実行するメソッド(手法)ではありえない。

==== クラスメソッド ====
[[メソッド (計算機科学)#静的メソッド|クラス・メソッド]]だが、オブジェクト指向の本義に立ち返れば、クラス・メソッドがあるということはクラスがメッセージをレシーブできるという事になる。

クラスがメソッドを持つことは便利だが、クラスをオブジェクトとすると実行効率に劣るため、双方の利点を享受できるこのような折中的仕様を取る言語は多い。

C++ではクラスはオブジェクトでは無いが、一方でクラスに属するメソッドは存在する。

[[Eiffel]]ではクラスはオブジェクトでは無いためクラスのメソッドであるクラス・メソッドは存在しない。

[[Smalltalk]]ではクラスもオブジェクトの一種であるため当然クラスはメソッドをもつ。

'''各言語におけるクラスメソッドの呼称'''

クラス・メソッドは、C++では'''静的メンバ関数''' ({{Lang|en|static member function}}) と呼ばれる。これはクラスがオブジェクトでない言語にとってはクラス・メソッドより正確な表現であり適切である。("static" とはCの'''static変数'''に由来し'''auto変数'''の対語である。関数コールによりスタック上に生成される関数インスタンスに依存しない変数と、インスタンス生成有無にかかわらず実行できる関数の類似による。)

Javaではクラス・メソッドは'''静的メソッド''' ({{Lang|en|static method}}) とも呼ばれることもある。

==== システムメソッド ====
言語によっては特定の名前のインスタンス・メソッドやクラス・メソッドにオブジェクトの生成、初期化、複製、廃棄といった機能を固定的に割り当てている。

==== コンストラクタとデストラクタ ====
初期化に利用されるメソッドを'''[[コンストラクタ]]'''あるいは'''構築子''' ({{Lang|en|constructor}})、廃棄時に利用されるメソッドを'''[[デストラクタ]]'''と呼んで特別に扱うことが多い。

コンストラクタが初期化だけを担う場合はイニシャライザあるいは初期化子 ({{Lang|en|initializer}}) と呼ばれることもある。

Javaはオブジェクトの寿命管理に[[ガベージコレクション]]を用いるため、デストラクタをサポートしない。ただし、オブジェクトがガベージコレクションによって破棄されるときに呼び出される'''[[ファイナライザ]]''' ({{Lang|en|finalizer}}) をサポートし、{{Javadoc:SE|name=Object#finalize()|java/lang|Object|finalize()}}メソッドがその役割を果たす。ただし、ファイナライザはC++のデストラクタと違ってユーザーコードで明示的に呼び出すことはできない。ファイナライザが呼び出されるタイミングをプログラマが制御することはできず、最終防壁(フェイルセーフ)としての役割しか持たないため、Javaにおけるファイナライザは本当に必要でない限り使用するべきではない。C#もファイナライザをサポートする(構文はC++のデストラクタに似ており、かつてはデストラクタと呼ばれていたが、役割はJavaのファイナライザと同じである)。

[[データ型]]の理論においては保持されるデータが必ずその型で認められる正しい値の範囲に収まることを保証するため、生成されるオブジェクトのデータ・メンバが必ず適切なコンストラクタによって初期化されるように求める。またオブジェクトが入出力機器や[[ファイル (コンピュータ)|ファイル]]や通信、[[プロセス]]や[[スレッド (コンピュータ)|スレッド]]、[[ウィンドウ]]と[[ウィジェット (GUI)|ウィジェット]]など[[ハードウェア]]や[[オペレーティングシステム]] (OS) が提供する資源を管理するために利用される場合に、コンストラクタやデストラクタでそれらの資源の使用開始(オープン処理)や使用終了(クローズ処理)をそれぞれ管理し、通常のメソッドでそれらにまつわる各種サービスを提供するようにすることで、それらのリソースがあたかもプログラム中のオブジェクトであるかのように自然に取り扱うことができるようになる([[RAII]])。

C++やJavaなどでは、コンストラクタはクラスと同じ名前を持ち、戻り値を持たないメソッドとして定義される。C++では一部のコンストラクタは[[型変換演算子]]として、また[[暗黙の型変換]]にも利用される。

=== ガベージコレクション ===
オブジェクト指向プログラミング言語では、オブジェクトへの[[参照 (情報工学)|参照]]や[[ポインタ (プログラミング)|ポインタ]]が多用される。そのため、オブジェクトの[[メモリ]]への割り当てと破棄に関して、[[ガベージコレクション]]による自動管理機能を備えているものが多い。ただし、すべての言語が備えているわけではない。例えば、C++はガベージコレクションを備えていない。

=== アクセスコントロール ===
オブジェクト指向プログラミングにおいて、[[オブジェクト (プログラミング)|オブジェクト]]は、[[カプセル化]]されておりブラックボックスである。したがって、処理するメッセージのカタログ、つまりインタフェースだけが利用者に公開され、内部の詳細は隠されるのが基本である。しかし、あるクラスのインスタンスの内部だけで利用されるメソッドまで公開してしまうと、利用者にとって煩雑である。また、定数データ・メンバのようなものは一々メソッドでアクセスするようにせず公開してしまっても、カプセル化の利点は失われず効率的でもある。そこで、オブジェクトを定義するプログラマが各データ・メンバやメソッドについて公開・非公開を設定できる機能を用意している言語は多い。

例えば、Javaでは、データ・メンバやメソッドの宣言にpublicと指定すれば、他オブジェクトから自由に利用でき('''公開'''と呼ばれる)、privateと指定すればオブジェクト内だけで利用できるようになる('''非公開'''と呼ばれる)。

しかし、ある機能を提供するのに、一個ではなく一群のクラスに属するオブジェクトでそれを記述するのが相応しい事例がある。そのような場合、関係する一群のオブジェクト間でだけデータ・メンバやメソッドを利用できれば便利である。それを可能にするための拡張がいくつか存在する。例えば、継承を利用しているときに、あるクラスが子孫にだけ利用を許可したいデータ・メンバやメソッドがある場合、Javaではprotectedを指定することでそれを実現できる('''限定公開'''と呼ばれる)。また、ある一群の機能を実現するクラスの[[ライブラリ]]で、その実現に関連するクラスに属するオブジェクトだけがデータ・メンバやメソッド利用できるようにしたい場合も考えられる。また、Javaでは、ライブラリを構成するクラス群を表現する'''[[パッケージ (Java)|パッケージ]]''' ({{Lang|en|package}}) という仕組みがあり、特に指定がない場合は同一パッケージに属するクラスのオブジェクト間でのみデータ・メンバやメソッドを相互に利用可能である。その他にも、[[デザインパターン (ソフトウェア)|デザインパターン]]の一つである[[Facade パターン]]では、この仕組みがテクニックとして応用されている。また、C++ではフレンド宣言という仕組みがあり、あるクラスで外部非公開に指定されているデータ・メンバやメソッドについて、その利用を許可するクラスや関数のリストをクラス内に列挙することができる。

なお、public、private、protectedというキーワードは、多くのプログラミング言語で用いられているが、その示す意味は言語ごとに差異があるため、注意が必要である。


== 脚注 ==
== 脚注 ==
304行目: 272行目:


== 関連項目 ==
== 関連項目 ==
{{Wikibooks|オブジェクト指向|オブジェクト指向}}
* [[メッセージ (コンピュータ)]]
* [[メソッド (計算機科学)]]
* [[フィールド (計算機科学)]]
* [[インスタンス変数]]
* [[クラス変数]]
* [[クラス (コンピュータ)]]
* [[インスタンス]]
* [[カプセル化]]
* [[継承 (プログラミング)|継承]]
* [[委譲]]
* [[プログラミング言語]]
* [[オブジェクト指向モデリング]]
* [[オブジェクト指向分析設計]]
* [[オブジェクト指向]]
* [[オブジェクトデータベース]]
* [[トップダウン設計とボトムアップ設計]]
* [[オブジェクト関係マッピング]]


{{Normdaten}}
{{Normdaten}}
{{プログラミング言語の関連項目}}
{{プログラミング言語の関連項目}}

{{デフォルトソート:おふしえくとしこうふろくらみんく}}
{{デフォルトソート:おふしえくとしこうふろくらみんく}}
[[Category:オブジェクト指向|*ふろくらみんく]]
[[Category:オブジェクト指向|*ふろくらみんく]]

2021年2月22日 (月) 05:42時点における版

オブジェクト指向プログラミング(オブジェクトしこうプログラミング、: object-oriented programming、略語:OOP)とは、互いに密接な関連性を持つデータ変数またはプロパティ)とコード関数またはメソッド)をひとつにまとめてオブジェクトとし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。

オブジェクト指向という用語自体は、計算機科学者アラン・ケイによって生み出されている。1962年公開の言語「Simula」にインスパイアされたケイが咄嗟に口にしたとされるこの造語は、彼が1972年から開発公開を始めた「Smalltalk」の言語設計を説明する中で発信されて1981年頃から知名度を得た。しかしケイが示したオブジェクト指向の要点であるメッセージングの考え方はさほど認知される事はなく、代わりにクラスオブジェクトという仕組みを注目させるだけに留まっている。同時にケイの手から離れたオブジェクト指向は抽象データ型を中心にした解釈へと推移していき、1983年に計算機科学者ビャーネ・ストロヴストルップが公開した「C++」が好評を博したことで、オブジェクト指向に対する世間の理解は「C++」とそのモデルの「Simula 67」のスタイルで定着した。それに基づいてカプセル化継承ポリモーフィズムといった考え方も後年に確立された。

特徴

クラスベースとプロトタイプベース

OOPというパラダイムは、クラスベースプロトタイプベースの二つのサブパラダイムに大別されている。クラスベースの代表格は「C++」「Java」「C#」であり、プロトタイプベースの代表格は「Python」「JavaScript」「Ruby」である。前者はクラスインスタンスの仕組みを中心にしており、後者はメタオブジェクトプロトコル英語版の仕組みを基礎にしている。前者は静的型付けを重視しており、後者は動的型付けを重視している。2000年代以降になるとプロトタイプベースもクラスの仕組みを積極的に取り入れるようになったので、純粋なプロトタイプベースの存在感は失われつつある。本節でもクラスベースを基準にして説明する。

クラスとインスタンス

OOPの要点であるクラスとは、端的に言うと変数と関数をひとまとめにしたものであり、手続きを付けたデータ構造体とも解釈される。コンパイル時定義の静的型付けが普通である。クラスに属する変数はデータメンバまたはデータと総称され、言語別にフィールド、プロパティ属性、メンバ変数といった名称になっている。クラスに属する関数はもっぱらメソッド、メンバ関数、メンバ手続きといった名称になっている。これだけの説明だとC言語Visual Basic系などの非OOP言語で使用されるモジュールと、OOP言語のクラスは同じものに見えるが双方の間には明確な違いがあり、モジュールに抽象abstraction)の考え方とその機能を導入したものがクラスである。抽象化のための機能とは後述のカプセル化継承ポリモーフィズムを指している。

クラスはデータとメソッドの構成を定義した型であるので、それを計算対象や代入対象になる値として扱うにはインスタンスに実体化(量化)する必要がある。その用法でのクラスはユーザー定義型と呼ばれる。クラスはインスタンスのひな型であり、インスタンスはクラスを量化したものである。ここでの量化とは、そのクラスに属する変数の値を全て決定してメモリに展開する行為を指す。言語によっては後述の仮想関数テーブルもセットで展開する。インスタンスは別名としてオブジェクトとも呼ばれる。OOPの主役であるオブジェクトの意味と用法は実は曖昧なのが現状であり言語ごとにも違いがある。

オブジェクト指向の三大要素

クラスベースOOPは抽象データ型の思想に準拠しており、その実装スタイルを規定した以下の三項目は、日本では三大要素または三大原則などと呼ばれている。非OOP言語のモジュールに三大要素仕様を加えたものがOOP言語のクラスになる。カプセル化はthis参照の機構とデータ/メソッドの可視性を指定できる機能、継承は自身のスーパークラスを指定できる機能、ポリモーフィズムはオーバーライド仮想関数テーブルを処理できる機能である。

カプセル化

互いに関連するデータとメソッドをまとめてクラスとし、必要なデータとメソッドのみを外部公開し、それ以外をクラス内に隠蔽する機能をカプセル化と呼ぶ。外部公開されたデータとメソッドはクラス外からの直接アクセスが可能である。内部隠蔽されたデータとメソッドはクラス外からアクセスされないことが保証されこれは情報隠蔽と呼ばれる。同クラス所属のメソッドを通してのデータの閲覧と変更はそのデータの抽象化を意味することになりこれはデータ抽象英語版と呼ばれる。この二つがカプセル化の要点である。データ抽象を実装するための仕組みでもあるthis参照については後節で述べられる。データ閲覧用メソッドはゲッター、データ変更用メソッドはセッターと呼ばれる。データとメソッドの外部公開範囲を、無制限・任意クラスグループ・派生クラスグループの三段階に分けて定義する機能はアクセスコントロールと呼ばれる。

継承

既存クラスのデータ/メソッド構成に任意のデータ/メソッド構成を付け足して、既存構成+新規構成の新しいクラスを定義する機能を継承と呼ぶ。その差分プログラミング目的の継承よりも、既存構成に抽象メソッドを置いて新規構成にその実体メソッドを置くというオーバーライド目的の継承の方が要点にされている。新規構成ではなく実装内容を付け足していくための継承である。既存クラスは基底クラス、親クラス、スーパークラスなどと呼ばれ、新しいクラスは派生クラス、子クラス、サブクラスなどと呼ばれる。抽象メソッドを持つクラスは抽象クラスと呼ばれる。継承できるクラスが一つに限られている単一継承を採用している言語と、継承できるクラスの数に制限がない多重継承を採用している言語に分かれている。抽象メソッドのみで構成される純粋抽象クラスの継承は、インターフェースの実装継承英語版と呼ばれて抽象化目的の継承になる。

ポリモーフィズム

異なる種類のクラスに同一の操作インターフェースを持たせる機能をポリモーフィズム(多態性)と呼ぶ。これはクラスの継承関係を利用して、コンパイル時のメソッド名から呼び出されるプロセス内容を実行時に決定するという仕組みを指す。その実装は仮想関数英語版と呼ばれており、クラスベースOOPのポリモーフィズムはイコール仮想関数となっている。仮想関数はスーパークラスの抽象メソッドの呼び出しを、それをオーバーライドしたサブクラスの実体メソッドの呼び出しにつなげる機能である。抽象メソッドとオーバーライド機能については後節で述べる。ポリモーフィスムの要点は、同じメソッド名からその実行時に対応した異なる処理内容を呼び出せるようにすることである。

コンポジションとデリゲーション

コンポジション(合成)とデリゲーション(委譲)は、継承の原型的仕組みであり、別の言い方をすると合成+委譲を最適化した機能が継承である。継承はis-a構造の委譲、合成はhas-a構造の委譲と読み替える事ができる。合成とは、クラスに特定処理の委譲先となる部品クラスを複数持たせた構造であり、合成クラスがデータ/メソッドを要求されて自身が未所持の場合は、対応可能な部品クラスを選択して委譲するという仕組みである。その要求判別と選択過程を自動化したのが継承であり、部品クラスを親クラスに置き換えて暗黙の委譲先にしたものである。しかしその暗黙委譲は実際に参照されるデータ/メソッドの把握を困難にするという欠点も明らかになったので、合成の価値が再認識されるようになった。既存構成に新規構成を付け足していく差分プログラミング目的では、継承よりも合成を用いる方がよいと考えられている。

動的ディスパッチとメッセージパッシング

動的ディスパッチはポリモーフィズムの原型的仕組みであり、継承構造上でのthis参照によるシングルディスパッチを最適化した機能が仮想関数である。動的ディスパッチはコンパイル時のメソッド名から呼び出されるメソッド内容が実行時に決定される仕組み全般を指す用語であり、メソッド名を基軸にして各引数の型によってプロセスが選択分岐される仕組みを意味するシングルディスパッチと多重ディスパッチを包括している。一つの引数の型がプロセス選択に影響するのはシングル、二つ以上なら多重になる。

メッセージパッシングでは、引数の型に加えてメソッド名も実行時に解釈される要素にされておりそれはセレクタと呼ばれる。object selector: paramような書式でオブジェクトの共通窓口となるメッセージレシーバーにセレクタと引数のメッセージが送られる。また、object.call(method_name, param)のような書式でオブジェクトの共通窓口関数をコールするのもメッセージパッシングと呼ばれる。これは遠隔手続きコールオブジェクト要求ブローカーで用いられており分散オブジェクトの標準的なインターフェース機構になっている。関数名も実行時に解釈されるという特徴を指してメッセージパッシングと呼ぶ。よく用いられるセレクタ対応プロセスを自動選択化してコンパイル時最適化した仕組みがメソッドになり、これは関数名をコンパイル時決定する関数呼び出しと同類になった。

インターフェース

インターフェースはカプセル化を更に突き詰めた仕組みであり、データ抽象とメソッド抽象と情報隠蔽を合わせて実現する最もOOPらしい機能と言える。インターフェースは抽象メソッドのみで構成されている純粋抽象クラスである。ゲッター、セッター、プロセスになる各抽象メソッドの実装内容は利用者側から隠されて実行時のその都度に決定される。

プロトタイプとオブジェクト

クラスベースのクラスと実体化とインスタンスは、プロトタイプベースではプロトタイプと複製とオブジェクトに置き換わる。プロトタイプとオブジェクトの大きな特徴は、プロパティとメソッドを自由に付け替えできることでありこれは動的バインディングとも呼ばれ、そのプロパティとメソッドの構成による型はダックタイピングで判別される。この特徴は同時にポリモーフィズムになる。その用法は関数オブジェクトと変数オブジェクト(値オブジェクト)に大別され、前者は二階述語論理、後者は高階述語論理の表現体になり、それ自体がメタ視点から抽象化されたオブジェクトにはカプセル化という概念は必要でなくなる。継承の意味合いも異なりクラスベースの基底と派生は、プロトタイプベースではプロパティ/メソッド構成のアタッチ候補とそのアタッチ先に置き換わる。アタッチ候補は親クラスやトレイトなどと呼ばれる。アタッチ候補は事実上のデリゲーション先でもある。トレイトは多重継承前提でありこれはミックスインと呼ばれ、構造的型付けでその実装継承が判別される。

プロトタイプベースは動的な関数型プログラミングに似た性質になっているが、オブジェクトの柔軟な用法に対しての一定の枠組みが必要であるとも考えられるようになり、静的なクラス定義が積極的に導入されるようになった。現状のプロトタイプベースは元来のメタオブジェクト構想から離れて、関数型とOOPのハイブリッドのようなパラダイムに落ち着いている。

アラン・ケイのメッセージング

メッセージングはオブジェクト指向の父であるアラン・ケイが最重視していた源流思想である。ここでは各自が解釈できるように彼の言葉をそのまま引用して本節の結びとする。

I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages.
(さながら生物の細胞、もしくはネットワーク上の銘々のコンピュータ、それらはただメッセージによって繋がり合う存在、僕はオブジェクトをそう考えている) — Alan Kay
... each object could have several algebras associated with it, and there could be families of these, and that these would be very very useful.
(銘々のオブジェクトは関連付けられた幾つかの「代数」を持つ、またそれらの系統群も持つかもしれない、それらは極めて有用になるだろう) — Alan Kay
The Japanese have a small word - ma ... The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.
(日本語には「間」という言葉がある・・・成長的なシステムを作る鍵とは内部の特徴と動作がどうあるべきかよりも、それらがどう繋がり合うかをデザインする事なんだ) — Alan Kay

歴史

1954年に初の高水準言語FORTRANが登場すると、開発効率の劇的な向上と共にソフトウェア要求度も自然と高まりを見せてプログラム規模の急速な拡大が始まった。それに対応するために肥大化したメインルーチンをサブルーチンに分割する手法と、スパゲティ化したgoto命令制御構造文に置き換える手法が編み出され、これらは1960年に公開された言語「ALGOL60」で形式化された。当時のALGOLはアルゴリズム記述の一つの模範形と見なされたが、それと並行して北欧を中心にした計算機科学者たちはより大局的な観点によるプログラム開発技法の研究を進めていた。

Simulaの開発(1962 - 72)

1962年、ノルウェー計算センターでモンテカルロ法シミュレーションを運用していた計算機科学者クリステン・ニゴールは、ALGOL60を土台にしてProcessと呼ばれるコルーチン機構を加えたプログラミング言語「Simula」を公開し、続けてその拡張にも取り組んだ。ニゴールの同僚で、1963年にSimulaを汎用機UNIVAC系統上で運用できるように実装した計算機科学者オルヨハン・ダールは、Processにローカル変数構造を共有する手続き(サブルーチン)を加えてパッケージ化する言語仕様を考案し、これは一定の変数と手続きをまとめるモジュールと同類の機能になった。程なくしてALGOL60コンパイラに準拠していての限界を悟ったニゴールとダールは、1965年からSimulaを一から再設計するように方針転換した。その過程で彼らは、計算機科学者アントニー・ホーアが考案して1962年のSIMSCRIPT(FORTRAN用のスクリプト)に実装していたRecord Classを参考にしている。Record Classはソースコード水準の抽象表現を、各汎用機に準拠したマシンコード水準の実装符号に落とし込む段階的データ構造のプログラム概念であった。これをモデルにした継承と、その継承構造を利用した仮想手続き(仮想関数)の仕組みも考案され、上述のパッケージ化されたProcess(モジュール)に継承と仮想手続きの両機能を加えたものを「クラス」と定義し、クラスをメモリに展開したものを「オブジェクト」と定義する言語仕様がまとまり、1967年に「Simula67」が初公開された。オブジェクトという用語は、MITの計算機科学者アイバン・サザランドが1963年に開発したSketchpadCADGUIの元祖)の設計内にあるObjectが先例であった。Simula67コンパイラはまずUNIVAC上で運用され、翌年から汎用機バロースB5500などでも稼働されて北欧、ドイツ、ソ連の各研究機関へと広まり、1972年にはIBM汎用機System/360などにも導入されて北米全土にも広まった。その主な用途は物理シミュレーションであった。

influenced by Sketchpad, Simula, the design for the ARPAnet, the Burroughs B5000, and my background in Biology and Mathematics, I thought of an architecture for programming.
SketchpadSimulaARPAネットバロースB5000、それと専攻していた生物学と数学に影響されて僕はプログラミングアーキテクチャを思索していた) — Alan Kay

構造化プログラミングの提唱(1969 - 75)

Simulaの普及と前後して1960年代半ばになると、プログラム規模の際限ない肥大化に伴う開発現場の負担増大が顕著になり、いわゆるソフトウェア危機問題が計算機科学分野全般で取り沙汰されるようになった。その解決に取り組んだ計算機科学者エドガー・ダイクストラは、1969年のNATOソフトウェア工学会議で「構造化プログラミング」という論文を発表しトップダウン設計、段階的な抽象化、階層的なモジュール化、共同詳細化(抽象データ構造と抽象ステートメントのjoint)といった構造化手法を提唱した。ダイクストラの言う構造化とは開発効率を高めるための分割統治法を意味していた。なおこの構造化プログラミングは後に曲解されて制御構造文を中心にした解釈の方で世間に広まり定着している。共同詳細化は抽象データ構造を専用ステートメントを通して扱うという概念である。これはSimulaの手続きを通してクラス内の変数にアクセスするという仕組みをモチーフにしていた。段階的な抽象化と階層的なモジュール化は時系列的にも、SIMSCRIPTの段階的データ構造と、Simura67の継承による階層的クラス構造を模倣したものであった。ダイクストラホーアダールの三名は1972年に『構造化プログラミング』と題した共著を上梓していることから互いの研鑽関係が証明されている。その階層的プログラム構造という章の中でダールは、Simulaの目指した設計を更に明らかにした。

I'm not against types, but I don't know of any type systems that aren't a complete pain, so I still like dynamic typing.
(僕は型アンチではないが、全くうんざりしない型システムも知らない、だからまだ動的型付けを好んでいる) — Alan Kay

1974年にMITの計算機科学者バーバラ・リスコフは「抽象データ型」というプログラム概念を提唱し、ダイクストラが提示したモジュールの共同詳細化を、その振る舞いによって意味内容が定義される抽象データという考え方でより明解に形式化した。一方、1970年に構造化言語Pascalを開発していた計算機科学者ニクラウス・ヴィルトは、ダイクストラによる共著出版後の1975年にモジュール化言語Modulaを提示してモジューラプログラミングというパラダイムを生み出している。このようにいささか奇妙ではあるが、Simulaのクラスとオブジェクトというプログラム概念は、巷で言われる構造化からモジュール化へといった進化の流れとは関係なく、しかもその前段階においてさながら彗星のように生まれたパラダイムであった。

Smalltalkとオブジェクト指向の誕生(1972 - 81)

Simula発のProcessとクラスの仕様は、パロアルト研究所の計算機科学者アラン・ケイによるオブジェクト重視と「メッセージング」という考え方のヒントになった。ケイはプログラム内のあらゆる要素をオブジェクトとして扱い、オブジェクトはメッセージの送受信でコミュニケーションするという独特のプログラム理論を提唱した。それには関数適用風の書式を用いたオブジェクト同士の多種多様なデリゲーションと、プログラムコードとしても解釈できるデータ列を送信してそれを評価(eval)することで新たなデータを導出できるなどのアイディアが盛り込まれていた。オブジェクトが送るか受け取ったメッセージは任意のタイミングで評価できるので非同期通信や単方向通信をも可能にしていた。この発想の背景にはLISPの影響があった。オブジェクトとメッセージングの構想に基づいて開発された「Smalltalk」はプログラミング言語とGUI運用環境を併せたものとなり、1972年にゼロックスAlto上で初稼働された。Smalltalkの設計を説明するためにケイが考案した「オブジェクト指向」という用語はここで初めて発信された。またケイのメッセージング構想はMITの計算機科学者カール・ヒューイットに能動的なプロセス代数を意識させて、1973年発表のアクターモデルのヒントにもなっている。しかしデリゲーションの多用とデータ列が常にコード候補として扱われる処理系は、当時のコンピュータには負荷が大きく実用的な速度を得られないという問題にすぐ直面した。Smalltalk-74とSmalltalk-76の過程で、やむなくメッセージは構想時の柔軟さが失われるほどシステム向けに最適化され、レシーバーはセレクタパターン重視のメソッド化が進み、オブジェクトは静的なクラス定義の存在感が大きくなった。

Smalltalk is not only NOT its syntax or the class library, it is not even about classes. I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea.The big idea is "messaging"...
(Smalltalkはその構文やライブラリやクラスをも関心にしていないという事だけではない。多くの人の関心を小さなアイディアに向かせたことから、僕はオブジェクトという用語を昔作り出したことを残念に思っている。大切なのはメッセージングなんだ。) — Alan Kay

1980年のSmalltalk-80は、元々はメッセージを重視していたケイを自嘲させるほど同期的で双方向的で手続き的なオブジェクト指向へと変貌していた。それでも動的ディスパッチと委譲でオブジェクトを連携させるスタイルは画期的であり、1994年に発表されるデザインパターンの模範にもされている。1981年に当時の著名なマイコン専門誌『BYTE』がSmalltalkとケイ提唱のオブジェクト指向を紹介して世間の注目を集める契機になったが、ケイの思惑に反して技術的関心を集めたのはクラス機構の方であった。オブジェクト指向は知名度を得るのと同時に、Simula発のクラスとそれを理論面から形式化した抽象データ型を中心に解釈されるようになり、それらの考案者がケイの構想とは無関係であったことから、オブジェクト指向の定義はケイの手を離れて独り歩きするようになった。

C++の開発と普及(1979 - 88)

Simulaを研究対象にしていたAT&Tベル研究所の計算機科学者ビャーネ・ストロヴストルップは、1979年からクラス付きC言語の開発に取り組み、1983年に「C++」を公開した。C++で実装されたクラスは、Simula譲りの継承と仮想関数に加えて、レキシカルスコープの概念をクラス構造に応用したアクセスコントロールを備えていた。C++で確立されたアクセスコントロールはカプセル化の元になったがコードスタイル上ほとんどザル化されており、その理由からストロヴストルップ自身もC++は正しくない(not just)オブジェクト指向言語であると明言している。1986年にソフトウェア技術者バートランド・メイヤーが開発した「Eiffel」の方は、正しいオブジェクト指向を標榜してクラスのデータ抽象を遵守させるコードスタイルが導入されていた。クラスメンバ(フィーチャー)は属性、手続き、関数の三種構成で、手続きで属性を変更し関数で属性を参照するという形式に限定されており、これは抽象データ型の振る舞い意味論に沿った実装であった。アクセスコントロールはモジューラプログラミングの情報隠蔽に沿った方式になり、仮想関数機能は延期手続き/関数として実装された。

I made up the term ‘object-oriented’, and I can tell you I didn’t have C++ in mind.
(僕はオブジェクト指向という言葉を作ったけど、C++(のような言語)は考えていなかった) — Alan Kay

1986年からACMオブジェクト指向会議(OOPSLA)を年度開催し、そのプログラミング言語セクションでは抽象データ型の流れを汲むクラス・パラダイムが主要テーマにされ、それを標準化するための数々のトピックが議題に上げられている。モジュール性、情報隠蔽、抽象化、再利用性、階層構造、複合構成、実行時多態、動的束縛総称型自動メモリ管理といったものがそうであり、参画した識者たちによる寄稿、出版、講演を通して世間にも広められた。そうした潮流の中でストロヴストルップはデータ抽象の重要性を訴え、リスコフ基底と派生に分けたデータ抽象の階層構造の連結関係について提言した。契約による設計を提唱するメイヤーが1988年に刊行した『オブジェクト指向ソフトウェア構築』は名著とされ、Eiffelを現行の模範形とする声も多く上がった。ただしこれは学術寄りの意見でもあったようで、世間のプログラマの間では厳格なEiffelよりも柔軟で融通の利くC++の人気の方が高まっていた。他方でオブジェクト指向本来の原点であるメッセージ・メタファに忠実であろうとする動きもあり、1984年に開発された「Objective-C」はSmalltalkをモデルにしてそれを平易化した言語であった。そのメッセージレシーバーは静的なメソッド機構優先の動的ディスパッチ機構という方式で実装された。メッセージレシーバの仕組みは遠隔手続き呼出し/オブジェクト要求ブローカーの実装に適していたので分散システムとオブジェクト指向の親和性を認識させることになった。

プロトタイプベースの黎明(1979 - 91)

アラン・ケイがその影響を言及していたLISPコミュニティでは1970年代後半から、Smalltalkが提唱するオブジェクト指向とLISPプログラミングの融合が研究されており、LISPのオブジェクト指向拡張版と称されたFlavorsがMIT人工知能研究所LISPマシン上で実装されるようになった。Flavorsのオブジェクト指向デザインはLISPの関数型思想で再解釈されつつCommon Lispに融合され、1988年に「Common Lisp Object System (CLOS)」が発表された。CLOSはメタクラス動的型付け多重ディスパッチの合わせ技であるジェネリック関数、構造的型付けと多重継承の合わせ技であるミックスイン、メソッドコンビネーションといった特徴的な機能を備えており、そのLISP風の動的型付けは後年に定義されるダックタイピングのルーツになり、メソッドコンビネーションの方はアスペクト指向のルーツになった。CLOSの設計思想は「メタオブジェクトプロトコル」の名でまとめられて1991年にパロアルト研究所フェローから著述発表されており、こちらはSmalltalkのEverythingIsAnObject思想をより具体化したプロトタイプベースのルーツになっている。また、同研究所でSmalltalkの方言として制作されていた「Self」が1987年に初回稼働され1990年に一般公開された。Selfにも導入されていたメタオブジェクト相当の仕様が、後にプロトタイプベースと呼ばれるオブジェクト指向スタイルに発展した。

The Art of the Metaobject Protocol ―
some of the most profound insights, and the most practical insights about OOP
(オブジェクト指向への最も深遠な洞察と、最も実用的な見識の数々) — Alan Kay

コンポーネントとネットワーク(1989 - 97)

ネットワーク技術の発展に連れて、データとメソッドの複合体であるオブジェクトの概念は、分散システム構築のための基礎要素としての適性を特に見出される事になり、IBM社アップル社サン社などが1989年に共同設立したOMGは、企業システムネットワーク向け分散オブジェクトプログラミングの標準規格となるCORBAを1991年に公開した。その前年にマイクロソフト社ウェブアプリケーション向けの分散オブジェクト技術となるOLEを発表し、1993年にはCOMと称するソフトウェアコンポーネント仕様へと整備した。このCOMの利用を眼目にしてリリースされた「Visual C++」「Visual Basic」はウェブ時代の新しいプログラミング様式を普及させる先駆になった。この頃に抽象データ型のメソッドを通したデータ抽象、データ隠蔽、アクセスコントロールおよび分散オブジェクト=プロセス間通信インターフェース機構によるプログラムの抽象化といった概念は、カプセル化という用語にまとめられるようになった。クラスの継承が最もオブジェクト指向らしい機能と見なされていたのが当時の特徴であった。継承構造を利用したサプタイピングは多態性という用語に包括され、多重継承の欠点が指摘されると分散オブジェクトのそれに倣ったインターフェースの多重実装設計が取り上げられた。こうしてカプセル化の誕生と連動するようにしていわゆるオブジェクト指向の三大要素がやや漠然と確立されている。1996年にサン社がリリースした「Java」は三大要素が強く意識されたクラスベースであり、その中の分散オブジェクト技術はBeansと呼ばれた。類似の技術としてアップル社もMacOS上でObjective-Cなどから扱えるCocoaを開発している。また、1994年から96年にかけて「Python」「Ruby」「JavaScript」といったオブジェクト指向スクリプト言語がリリースされ、従来のクラスベースに対するプロトタイプベースという新しいオブジェクト指向スタイルを定着させている。1994年のGOFデザインパターンの発表と、1997年にOMGが標準モデリング言語として採用したUMLは、オブジェクト指向プログラミングの標準化を促進させた。

... there were two main paths that were catalysed by Simula. The early one (just by accident) was the bio/net non-data-procedure route that I took. The other one, which came a little later as an object of study was abstract data types, and this got much more play.
(Simulaを触媒にした二本の道があった。最初の一本はバイオネットな非データ手法で僕が選んだ方。少し遅れたもう一本は抽象データ型、こっちの方がずっと賑わっている。) — Alan Kay

代表的なオブジェクト指向言語

オブジェクト指向言語は、抽象データ型に準拠したクラスベースメタオブジェクトプロトコル英語版を採用したプロトタイプベースSmalltalkを規範にしたメッセージングベースの三タイプに分類されるのが一般的である。クラスベースでは「C++」「Java」「C#」が代表的である。プロトタイプベースでは「Python」「JavaScript」「Ruby」が有名である。メッセージングベースでは「Smalltalk」「Objective-C」「Self」などがある。言語仕様の中でオブジェクト指向の存在感が比較的高い代表的なプログラミング言語は以下の通りである。

Simula 67 1967年
1962年に公開されたSimulaの後継バージョンであり、クラスのプログラム概念を導入した最初の言語である。物理モデルを解析するシミュレーション制作用に開発されたもので、クラスをメモリに展開したオブジェクトはその観測対象要素になった。Simulaのクラスは、一つのローカル変数構造と複数のプロシージャをまとめたミニモジュールと言えるものであったが、継承と仮想関数という先進的な設計を備えていた事でオブジェクト指向言語の草分けと見なされるようになった。クラスベースの源流である。
Smalltalk 1972年
メッセージングのプログラム概念を導入した最初の言語。数値、真偽値、文字列から変数、コードブロック、メタデータまでのあらゆるプログラム要素をオブジェクトとするアイディアを編み出した最初の言語であり、プロトタイプベースの源流にもなった。オブジェクト指向という言葉はSmalltalkの言語設計を説明する中で生み出された。オブジェクトにメッセージを送るという書式であらゆるプロセスを表現することが目標にされている。動的ディスパッチと動的バインディング相当の機構であるメッセージレシーバーデリゲーションは、後年のデザインパターンのモデルにもされた。GUI運用環境に統合された専用のランタイム環境上で動作させる設計も模範にされ、これは後に仮想マシン仮想実行システムと呼ばれるものになる。
C++ 1983年
C言語クラスベースのオブジェクト指向を追加したもの。Simulaの影響を受けている。静的型付けクラスが備えられてカプセル化、継承、多態性の三仕様を実装している。カプセル化ではアクセス修飾子とフレンド指定子の双方から可視性を定義できる。継承は多重継承、オーバーライド制約用の継承可視性、菱形継承問題解決用の仮想継承も導入されている。多態性は仮想関数によるサブタイプ多相、テンプレートクラス&関数によるパラメトリック多相、関数&演算子オーバーロードによるアドホック多相が導入されている。元がC言語であるため、オブジェクト指向から逸脱したコーディングも多用できる点が物議を醸したが、その是非はプログラマ次第であるという結論に落ち着いた。
Objective-C 1984年
C言語メッセージングベースのオブジェクト指向を追加したもの。こちらはSmalltalkの影響を受けており、それに準じたメッセージパッシングの書式が備えられた。メッセージを受け取るクラスの定義による静的型付けと共に、メッセージを委譲するオブジェクトの実行時決定による動的型付けも設けられている。オブジェクト指向的にはC++よりも正統と見なされた。制御構造文が追加され、メッセージ構文も平易化されており、Smalltalkよりも扱いやすくなった。
Object Pascal 1986年
Pascalにクラスベースのオブジェクト指向を追加したもの。当初はモジュールのデータ隠蔽的なカプセル化、単一継承、仮想関数による多態性という基本的なものだった。静的型付け重視である。ヴィルト監修のアップル社による初回バージョンを土台にして様々な企業団体による派生版が公開されており、その特徴と機能追加も様々である。
Eiffel 1986年
C++の柔軟性と融通性とは正反対のオブジェクト指向言語。クラスベース静的型付け重視である。契約による設計に基づくアサーションの挿入でクラスの状態および演算用の引数と返り値を細かくチェックできる。例外処理も備えられている。クラスメンバ(フィーチャー)はデータ、アクセッサ、ミューテイタの三種限定でオーバーロードはできない。カプセル化の可視性は自身に依存するクラス(クライアント)を定義する形で決められる。多重継承可能であり、クラス間の繋がりを仮想継承機能、各種オーバーライド指定子、名前衝突を解決するリネーミング機能などで綿密に設定できる。多態性は延期関数/手続き(サブタイプ多相)とジェネリシティ(パラメトリック多相)である。ガーベジコレクション機能が初めて導入されたオブジェクト指向言語でもある。
Self 1987年
メッセージングベースのオブジェクト指向言語でSmalltalkの方言として開発された。それ故にプロトタイプからプロトタイプを派生させ、またインスタンスを複製してそれにプロパティとメソッドを動的バインディングできるというメタオブジェクトプロトコルも忠実に実装された。プロトタイプベースというパラダイムはこのSelfから認知されるようになった。動的型付け重視である。Smalltalkと同様に専用のランタイム環境上で実行され、GUI運用環境の構築も目標にしていた。Selfのランタイム環境は実行時コンパイラ機能を初めて実装したことで知られており画期的な処理速度を実現している。この技術はJava仮想マシンの土台になった。
Common Lisp(CLOS) 1988年(ANSI規格化は1994年)
クラスベースのオブジェクト指向。メソッド記述の関数呼び出し形式への統合、多重ディスパッチ、クラスの動的な再定義等を特徴とする。
Python 1994年
プロトタイプベースのオブジェクト指向スクリプト言語。基本データ型コレクション型などよく使われるデータ要素を全て組み込みのオブジェクトにしている。それらは手続き型スタイルでも気軽に扱える。コレクション型を扱うのに適した関数型構文も導入されている。関数/変数のオブジェクトは自由にプロパティとメソッドを付け足し付け替え可能である。オブジェクトはダックタイピングで型判別されるので変数/関数の型宣言と型注釈は撤廃されている。ゆえに動的型付け重視である。Pythonのプロトタイプはクラスと呼ばれている。多重継承可能であり親クラス要素のサーチ順序はC3線形化で解決されている。多態性は事実上メソッドの動的バインディングになっている。カプセル化は軽視されている。後期バージョンで型ヒントが追加され、それに伴いジェネリクスも導入された。
Java 1995年
C++をモデルにしつつ堅牢性とセキュリティを重視したクラスベースのオブジェクト指向言語。静的型付け重視である。パッケージ中心のカプセル化、単一のみの継承、仮想関数と多重実装可なインターフェースによる多態性と、基本に忠実なクラスベースである。C++風のポインタと値型インスタンスは除外されて参照型インスタンスに統一した。例外処理を整備し演算子オーバーロードを除外した。オブジェクト指向とマルチスレッドの調和が図られ、コンポーネント指向による動的クラスローディングの存在感が高められている。クラスメタデータを操作できるリフレクションは初期から採用された。中期からジェネリクス(パラメトリック多相)とメタアノテーション(アドホック多相)が導入され、ラムダ式と関数型インターフェースを軸にした関数型構文も採用された。仮想マシン上で実行される。仮想マシンガーベジコレクションの技術は比較的高度と見なされている。
Delphi 1995年
Object Pascalを発展させたもの。それと同様にこちらも基本に忠実なクラスベースで静的型付け重視であった。当初はデータベース操作プログラム開発を主な用途にして公開された。クラスとレコード(構造体)に同等の比重が置かれていた。一時期Javaの対抗馬になった。
Ruby 1996年
Pythonを意識して開発されたオブジェクト指向スクリプト言語。Smalltalkを一つの理想にしてより万人向けの言語を目指し、動的型付けを重視している。日本で誕生してグローバル化したプログラミング言語である。LISPとSmalltalkのメタプログラミング的なオブジェクト指向から、PythonとJavaScriptのプロトタイプベースなオブジェクト指向までのスタイルとコーディング手法を幅広く取り入れている。
JavaScript 1996年
プロトタイプベースのオブジェクト指向スクリプト言語。型宣言と型注釈を撤廃してダックタイピングする動的型付け重視である。すべてをオブジェクトにするSmalltalkの思想に忠実な言語であり、Pythonと似ているがそれよりもプロトタイプベース性質と関数型プログラミング性質を追求している。定数、変数、構造体、関数などが全て同性質のオブジェクトにされており、プロパティとメソッドを自由に付け足したり付け替えできるようにデザインされている。関数オブジェクトの構築と用い方がプログラミング上のキーポイントになっており、クロージャ高階関数第一級関数、デコレータ、パイプラインといった多種多様な働き方とその組み合わせを柔軟に表現できる。WEBアプリケーション開発を主な用途にして公開されたのでオブジェクトはGUIパーツの構築にも最適化されている。ECMAScriptとして標準化されており、2015年版からはクラスベース向けの構文もサポートするようになった。
C# 2000年
Javaを強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。Javaよりもマルチパラダイムの性質が強化されている。C++譲りの柔軟性と融通的を残しながら様々な糖衣構文サポートも加えてコーディング上の利便性がより高められている。マルチスレッド仕様も整備されている。アドホック多相では拡張メソッド、インデクサ、演算子オーバーロードなどを備えている。パラメトリック多相では共変/反変も扱えるジェネリクスを備えている。サブタイプ多相はクラスは単一継承でインターフェースは多重実装と基本通りである。関数型構文も整備されており、特にメソッド参照機能であるデリゲートの有用性が高められている。デリゲートはイベント駆動構文の平易な表現も可能にしている。基本は静的型付けであるが、動的束縛型とダックタイピングによる動的型付けの存在感が高められているので漸進的型付けの言語と見なされている。.NET Framework共通言語基盤=仮想実行システム)上で実行される。
Scala 2003年
クラスベースのオブジェクト指向と関数型プログラミングを融合させた言語。クラス機構と関数型の型システムに同等の比重が置かれており静的型付け重視である。ミックスイン相当のトレイトと、共変/反変および抽象タイプメンバを扱えるジェネリクスを連携させた多態性が重視されておりオブジェクトを様々に派生型付けできる。シングルトンオブジェクトの役割が形式化されて従来のクラス静的メンバの新解釈にも用いられている。専用の定義書式によりイミュータブルなオブジェクトが重視されている。上述の派生型付けスタイルとオブジェクト引数の抽出構文とパターンマッチング式の併用連鎖計算はモナドを彷彿とさせて独特の関数型スタイルを表現できる。Java仮想マシン上で動作するJavaテクノロジ互換言語である。
Kotlin 2011年
静的型付けのクラスベースのオブジェクト指向であるが、手続き型プログラミングに回帰しており、クラス枠外の関数とグローバル変数の存在感が高められている。クラスはpublicアクセスとfinal継承がデフォルトにされて、カプセル化と継承が公然と軽視されている。これによりインスタンスは手続き型の関数の対象値としての役割が強められ、その操作をサポートする関数型構文も導入されている。仮想関数と抽象クラスによる多態性は標準通りである。Java仮想マシン上で動作するJavaテクノロジ互換言語である。
TypeScript 2012年
JavaScriptを強く意識してマイクロソフト社が開発したオブジェクト指向スクリプト言語。JavaScriptのプログラムを静的型付けで補完した言語である。クラスベース向けの構文と、関数型プログラミング型システムのスタイルが加えられている。特に後者の性質が強調されている事から静的型付け重視である。継承構造によるサブタイプ多相はほぼ除外されており、ジェネリクスと型アノテーションでオブジェクトを扱うというパラメトリック多相とアドホック多相を重視するデザインになっている。オブジェクト指向ではあるが関数型の性格が強めである。
Swift 2014年
Objective-Cを発展させたものであるが、メッセージ構文は破棄されており、クラスベースのオブジェクト指向になっている。オブジェクトのイミュータブル性重視の構文が採用されている。プロテクト可視性の削除によってクラスの縦並びの継承は軽視されており、プロトコルの横並びの多重実装を重視している。プロトコルはインターフェースミックスインの中間的機能であり、インスタンスはプロトコルを基準にして型分類され、また抽象化される。プロトコルとジェネリクスの連携による多態性が重視されている。モジュールの動的ローディングは不透明型の仕組みで補完されている。静的型付け重視である。

用語と解説

クラス
class)の仕組みを中心にしたオブジェクト指向をクラスベースと言う。クラスはデータとメソッドをまとめたものであり、操作的意味論を付加された静的レコードとも解釈される。クラスはインスタンスのひな型であり、インスタンスはクラスを実例化(量化)したものである。クラスはカプセル化、継承、多態性の三機能を備えていることが求められている。カプセル化はthis参照の仕組みの実装およびデータとメソッドの可視性を指定できる機能である。継承は自身のスーパークラスを指定できる機能である。多態性はオーバーライド仮想関数テーブルを処理する機能である。コンストラクタとデストラクタの実装も必要とされている。前者はインスタンス生成時に、後者はインスタンス破棄時に呼び出されるメソッドである。
プロトタイプ
prototype)の仕組みを中心にしたオブジェクト指向をプロトタイプベースと言う。プロトタイプとは識別名&中間参照ペアの集合体を指す。この集合体は一般にフレームと呼ばれる。識別名&中間参照ペアの割り当て箇所は一般にスロットと呼ばれる。スロットにはデータとメソッドの識別名&中間参照ペアが代入されるので、プロトタイプはクラスと同様にデータとメソッドをまとめたものになる。プロトタイプは言語によってはクラスと呼ばれている。プログラマはシステムが提供する基底プロトタイプに、自由にデータとメソッドを付け足して任意の派生プロトタイプを作成できる。プロトタイプは「型」相当であり、それを複製する方式で生成されるインスタンスは「値」相当である。データとメソッドはその参照にインスタンスを必要とするものと、しないものに分かれる。前者はインスタンスメンバ、後者は静的メンバに相当するものである。インスタンスにも自由にデータとメソッドを付け足すことができる。インスタンスはそのプロトタイプへの参照を保持しており、プロトタイプはその親プロトタイプへの参照を保持している。これは継承相当の機能になっている。インスタンスへの自由なメンバ付け替えは多態性相当の機能になっている。ただしプロトタイプは動的な関数型言語由来の仕様なのでクラスベースOOPの三大要素とはまた違った視点から眺める必要がある。
メッセージ
オブジェクト指向で言われるメッセージ(message)とは、オブジェクトの呼び出し側と呼び出される側の間であらゆる事柄が実行時に決められる仕組み全般を指す用語である。関数名の解釈、引数構成、返り値構成、関数名対応プロセス所有の是非、委譲先、同期/非同期タイミングといったものが実行時のその都度に決められる。実行時に解釈される関数名文字列はセレクタと呼ばれる。これは無制限に柔軟な仕様の関数呼び出しと考えてもよく、その実装方法の明確な定義は不可能である。代表例を挙げると分散オブジェクトや分散システムで用いられているメッセージパッシングは、関数名も実行時に解釈できる引数要素にした仕組みである。Smalltalk指向の言語に導入されているメッセージレシーバーとメソッドミッシングでは、特定のセレクタに対応するプロセスをコンパイル時定義できるようにして自動実行時選択されるようになっており、プロセス未定義セレクタだけが実行時解釈される仕組みになっている。このコンパイル時定義のセレクタプロセスをメソッドと呼んだ。OOPでメンバ関数をわざわざメソッドと呼ぶのはメッセージパッシング由来のこうした経緯からである。アラン・ケイはメッセージング(messaging)というより遠大な構想を持っていた。
インスタンス
instance)はクラスベースではクラスを実例化(量化)したものであり、実装レベルで言うとデータ群と仮想関数テーブルをメモリ上に展開したものになる。プロトタイプベースではプロトタイプを複製する方式で生成されたオブジェクトを指す。実装レベルで言うとメモリ上に展開された識別名&中間参照ペアの動的配列になる。
データメンバ
data member)はクラスに属する変数。データ(data)とも略称される。言語によってフィールド(分節)、プロパティ(特性)、アトリビュート(属性)、メンバ変数と呼ばれる。データは、クラスデータとインスタンスデータに分かれる。クラスデータは静的データとも呼ばれる。その中で定数化されたものはクラス定数と呼ばれる。クラスデータはクラス名の名前空間でスコープされたグローバル変数と同じものであり、プログラム開始時から終了時まで確保される。インスタンスデータはインスタンス生成時にメモリ上に確保されるものであり、その破棄時に消滅する。インスタンスデータの参照にはそのthis参照が必要である。プロトタイプベースでは、プロトタイプで定義されたデータでそのアクセスにインスタンス(self)を必要としないものが静的データになる。
メソッド
method)はクラスに属する関数。言語によってはメンバ関数、メンバ手続きとも呼ばれる。データの参照に特化したものはゲッター(getter)アクセッサ(accessor)と呼ばれる。データの変更に特化したものはセッター(setter)ミューテイタ(mutator)と呼ばれる。メソッドは、クラスメソッドとインスタンスメソッドに分かれる。クラスメソッドは静的メソッドとも呼ばれる。クラスメソッドはクラス名の名前空間でスコープされたグローバル関数と同じものである。インスタンスメソッドを呼び出すにはそのthis参照が必要である。プロトタイプベースでは、プロトタイプで定義されたメソッドでそのアクセスにインスタンス(self)を必要としないものが静的メソッドになる。
コンストラクタ
constructor)はインスタンス生成時に呼び出されるそのクラスのメソッドである。インスタンスデータを任意の値で初期化するためのものであるが、その他の初期化コードも記述できる。プロトタイプベースではシステム提供プロトタイプが保持する生成用メソッドまたは生成用のグローバル関数がコンストラクタ相当になる。
デストラクタ
destructor)はインスタンス破棄時に呼び出されるそのクラスのメソッドである。インスタンス破棄の影響を解決する任意の後始末コードを記述できる。インスタンスの破棄は占有メモリの解放を意味する。なお、ガーベジコレクタ実装言語ではファイナライザになっている事がある。プログラマが呼び出すデストラクタの方はその終了がメモリ解放に直結しているのに対し、ガーベジコレクタが呼び出すファイナライザの方はそうではない。
this参照
this)は言語によっては「self」や「me」とも呼ばれる。instance.method()の書式で呼び出されたメソッド内で、そのインスタンスのメンバを暗黙アクセスできるようにするための仕組みである。instanceのアドレスが暗黙引数としてmethodに渡されて、そのmethod内でthisとなる。インスタンスのメンバアクセス時はこのthisが自動的に付加され、例えばdataがシステム内ではthis.dataのように変換されている。メソッドはインスタンスの実体化元(量化元)クラスで定義されているものである。これは、データにメソッドを付属させるカプセル化を実現するための仕組みである。this参照に対するsuper参照(super)は、サブクラスのインスタンスメソッド内で用いられるものであり、直上スーパークラスのデータ/メソッドにアクセスするための参照である。オーバーライドやドミナンスを無視してスーパクラスのメンバを呼び出すための仕組みである。
アクセスコントロール
access control)は、カプセル化の情報隠蔽に基づいた機能であり、クラス内のデータとメソッドの可視性を決定する。可視性とはそれにアクセス(参照/変更)できる範囲を意味する。これにはレキシカルスコープ基準とクライアント基準の二通りがあるが、前者の方が一般的である。広く使われているレキシカルスコープ基準の可視性は、プライベート、プロテクト、パブリックの三種が基本である。プライベートは同クラス内のメンバからのみ、プロテクトは同クラス内と派生クラス内のメンバからのみ、パブリックはどこからでもアクセス可能である。クライアント基準の可視性は、自身メンバへのアクセスを許可するクライアントクラス(フレンドクラス)を定義する方法で決められる。そのクライアントの許可は同時にその派生クラスの許可も兼ねている事が多く、継承によるクラス群の一括定義を可能にする。
コピーコンストラクタ
copy constructor)は、メソッドの引数に対する値インスタンスの値渡しの時に呼び出されるコンストラクタである。値渡しはインスタンス内容全体のメモリコピーであり、基本データ型では特に問題は生じないが、そうでないクラスのインスタンスでは例えばあるリソースへの参照を保持している場合に好ましくない保持重複が発生する事になる。呼び出されたコピーコンストラクタは値インスタンスを受け取り、単純コピーが許されない部分に任意の処理を施して生成した値インスタンスのコピーを引数へと渡す。
オーバーロード
overloading)は、同じメソッド名(返り値の型+メソッド名)にそれぞれ異なるパラメータリスト(引数欄)を付けたものを列挙してメソッドを多重定義する仕組みを指す。演算子もオーバーロード対象であり、単項演算子なら一つの引数の型、二項演算子なら二つの引数の型を多重定義することで演算対象の値の型ごとに計算内容をカスタマイズできる。任意個数の引数を多重定義できる( )演算子は、クロージャまたは関数オブジェクトの表現に用いられる。
オーバーライド
method overriding)は、基底クラスで定義されたメソッド名義の呼び出しを、派生クラスで実装されたメソッド内容の実行につなげる機能である。これは基底メソッドを派生メソッドで上書きすると形容される。オーバーライドされた基底メソッドの内容はスルーされて派生メソッドの内容が実行される。メソッドシグネチャ(返り値の型+メソッド名+各引数の型と個数)が完全一致している基底側が派生側でオーバーライドされる。オーバーライド指定は、基底側のメソッドをvirtualやabstractで修飾する方式と、派生側のメソッドをoverrideやredefineで修飾する方式がある。前者では基底側でオーバーライド可否の定義が固定されるのに対して、後者では派生側で再定義できる。finalで修飾されたメソッドは再定義不可のオーバーライドの拒絶になる。オーバーライドメソッドの呼び出しは、基底クラスの型に代入された派生クラスのインスタンスで行われる。オーバーライドによって呼び出される内容が多相化されたメソッドは仮想関数と呼ばれる。仮想関数テーブルvirtual method table)はその多相化のための仕組みであり、メソッドシグネチャとメソッド内容アドレスがマッピングされている。
ドミナンス
dominance)は言語によってハイディング(hiding)マスキング(masking)とも呼ばれる。継承による階層的クラス構造において、サブクラスのメンバがスーパークラスの同名のメンバを隠していることを指す。親クラスのAメソッドを子クラスが同名Aメソッドでドミナンスした場合、子の型で参照しているインスタンスはそこでAのサーチが止まって子Aが呼び出される。ただし親の型で参照すれば親Aを呼び出せる。オーバーライドと異なり、参照する型でインスタンスの振る舞いを変えるための単純な仕組みでもある。
仮想継承
virtual inheritance)は、多重継承での菱形継承問題を回避するための仕組みである。菱形継承問題とは共にAクラスを親とするBクラスとCクラスの双方を継承した場合に、その継承構造上でAクラスが二つ重なって存在することになる不具合である。仮想継承では専用のテーブルが用意されて、そこでクラス名が参照アドレスにマッピングされる。BクラスからのAクラスと、CクラスからのAクラスは共に同じ参照アドレスをマッピングするのでAクラスはひとつにまとめられる事になる。同時に一度辿ったクラスは省略される事にもなる。
MRO
メソッド解決順序(method resolution order)は、多重継承時の親クラスの巡回順序を定義するものである。参照されたメソッドが自クラスにない場合はその親クラスを巡回してサーチされる。メソッドはクラスメンバと読み替えてもよい。これは深さ優先検索deep-first)と幅優先検索breadth-first)に分かれるが、オブジェクトの構造概念から深さ優先の方が自然とされている。従って一般的な多重継承では深さ優先検索が用いられて親クラスの重複は仮想継承で解決されている。しかし詳細は割愛するが、仮想継承部分の巡回順序に不自然さを指摘する意見もあったので、これを解決するために深さ優先と幅優先をミックスしたC3線形化(C3 linearization)というメソッド解決順序が考案された。C3線形化では親クラスの重複部分に対してのみ幅優先検索を適用することで、仮想継承を用いることなく菱形継承問題も自然に解決されている。
抽象クラス
abstract class)は、全部または一部のメソッドが抽象化されているクラスを意味する。即ち抽象メソッドを持つクラスである。抽象メソッド(abstract method)は、メソッドシグネチャ(返り値の型+メソッド名+各引数の型と個数)だけが定義されてコード内容が省略されているメソッドである。抽象クラスはインスタンス化できないので継承専用になる。抽象メソッドはそのサブクラスの方でコード内容が実装されてオーバーライドされる。
インターフェース
interface)はプログラム概念と機能名の双方を指す用語である。言語によってはプロトコルと言われる。抽象メソッドと実体メソッドをメンバにする純粋抽象〜半抽象クラスを意味する。一般的にデータはメンバにされない。クラスの振る舞い側面を抜き出した抽象体である。クラスによるインターフェースの継承は実装と呼ばれる。多重実装可が普通である。ミックスインとの違いは、抽象階層に焦点が当てられている事であり、直下の実装オブジェクトを共通の振る舞い側面でまとめることがその役割である。インターフェースは自身の下位概念である実装継承オブジェクトをグループ化できる。記名的型付け英語版に準拠しているのでインターフェースの実装の明記が振る舞い側面の識別基準になる。インターフェースは抽象メソッド主体なので多重継承時のメンバ名の重複はあまり問題にならない。共通の実装メソッドに集約されるからである。インターフェースは非インスタンス対象である。
ミックスイン
mixin)はインターフェースに似たプログラム概念を指す用語である。機能名は言語によってトレイト、プロトコル、構造型(structural type)と言われる。抽象メソッドと実体メソッドとデータをメンバにする継承専用クラスを意味する。クラスを特徴付けるための構成パーツである。クラスによるトレイトの継承は実装と呼ばれる。多重実装可が普通である。インターフェースとの違いは、トレイトの実装階層に焦点が当てられている事であり、オブジェクトを所有メンバで特定してまとめることがその役割である。トレイトは自身の上位集合である実装継承オブジェクトをグループ化できる。構造的型付け英語版に準拠しているので所属メンバ構成自体がトレイト等価性の識別基準になる。これはトレイト実装を明記していなくても、そのトレイトが内包する全メンバを所持していれば同じトレイトと見なされることを意味する。トレイトは合成や交差が可能である。トレイトは多重継承時のメンバ名重複の際にその参照の優先順位に注意する必要がある。トレイトは非インスタンス対象である。
型イントロスペクション
(type introspection)は一般に実行時型チェックと呼ばれるものである。プログラマが認知できない形でコンパイラまたはインタプリタが別途実装しているインスタンスの型情報を、実行時にその都度参照してインスタンスの型を判別する仕組みである。静的型付け下では専用の実行時型チェック構文(instanceofやdynamic_cast)によって型判別し、ダウンキャストなどに繋げられる。動的型付け下では変数への再代入時や関数への引数適用時にランタイムシステムが自動的に型判別し、多重ディスパッチなどに繋げられる。型イントロスペクションでは型情報のタグ識別子が判定基準になっているので記名的型付け英語版の考え方に準じている。
ダックタイピング
(duck typing)は、特定のメソッド名(メソッドシグネチャ)またはプロパティ名(データ名)の識別子を持っているかどうかでインスタンスをその都度分類する仕組みである。これはその場限りの型判別と言えるものである。判別されたインスタンスは自身が持つとされたメソッドまたはプロパティを呼び出される事になる。動的型付けの機能であり、ダックタイピングでは型情報の構成内容が判定基準になっているので構造的型付け英語版の考え方に準じている。
型推論
オブジェクト指向下の型推論(type inference)は、型宣言ないし型注釈を省略して定義された変数の「型」が自動的に導き出される機能を指す。型はクラスと同義である。静的型付けの機能であり、コンパイラまたはインタプリタがソースコードをあらかじめ解析し、初期値の代入を始めとしたその変数の扱われ方によって型を導き出す。ここで導き出される「型」とは他の変数への代入可能性や、関数の引数への適用可能性といったあくまで等価性の基準で決められるので、プログラマが人為的な意味付けによる型定義を重視している場合は予期せぬ結果が発生することにもなる。型推論は推論的型付け英語版とも呼ばれ、普通に型宣言と型注釈を用いる明示的型付け英語版の対極に位置付けられるが、昨今のオブジェクト指向言語では双方を併用するのが主流になっている。
メタクラス
metaclass)はメタオブジェクトプロトコル英語版に準拠した機能名であり、実装方式は言語毎に違いがある。メタクラスは、クラスのデータ、メソッド、スーパークラス、内部クラスなどの定義情報を記録したメタデータである。クラスベースのメタクラス機能は、実装レベルではシステム側が用意している特別なシングルトンオブジェクトと考えた方が分かりやすい。それにはほとんどの場合システム側が提供する抽象インターフェースを通してのみアクセスできる。メタクラス内容を閲覧/変更できる機能はリフレクションと呼ばれる。プロトタイプベースでは、インスタンスの複製元であるプロトタイプまたはクラスがメタクラス機能も備えており、データとメソッドの静的な事前定義の他、実行時にも動的にデータとメソッドを付け替えできる。プロトタイプないしクラスもプログラマが自由に扱えるオブジェクトになっている。
リフレクション
reflection)は、メタクラス内容を閲覧/変更する機能であるが、変更できる内容範囲は言語ごとに異なっている。データではデータ型、識別子、可視性が変更対象になる。メソッドではリターン型、識別子、パラメータリスト、可視性、オーバーライド指定が変更対象になる。双方の追加定義と削除もできる事がある。スーパークラスも変更できる事がある。メタクラスの変更はそのまま関連クラスと関連インスタンスにリフレクション(反映)される。ただし反映範囲はこれも言語によって異なる。
また、実行時の文字列(char配列やString)をデータとメソッドの内部識別子として解釈できる機能もリフレクションであり、上述のメタクラス操作よりもこちらの方がよく用いられる。これは実行時の文字列データを用いてのデータ/メソッドへの動的なアクセスを可能にする。
メタアノテーション
metadata annotation)はクラスに任意の情報を埋め込める機能である。情報とは文字列と数値からなるキーワード、シンボル、テキストである。プログラマが自由な形式で書き込んで随時読み取るものであるが、システムから認識される形式のものもある。実装レベルではメタクラスに書き込まれてリフレクション機能またはその糖衣構文で読み取ることになる。マーカーインターフェースの拡張とも見なされている。メタアノテーションはクラス単位だけでなく、言語によってはインスタンス単位やメソッド単位でも埋め込むことができる。
メソッド拡張
method extension)は、クラス定義とは別の場所でそのクラスに対する追加メソッドを定義できる機能である。これは状況に合わせてデータ抽象の表現に幅を持たせることを目的にしている。これには数々の書式があるが代表的なのは、静的メソッドまたは静的関数の第1引数をthis修飾して、その第1引数のクラス(型)に対してその静的メソッドをインスタンスメソッドとして追加するというものである。静的メソッドはそのクラススコープ内の限定拡張にできる。静的関数はネスト関数にしてそのローカルスコープ内の限定拡張にできる。双方はグローバル用途にすることもできる。
動的ディスパッチ
dynamic dispatch)は、コンパイル時のメソッド名から呼び出されるメソッド内容が実行時に決定される仕組み全般を指す用語である。メソッドに引数を渡しての呼び出しを、オブジェクトにメッセージを発送(ディスパッチ)することになぞらえた事が由来である。発送先は実行時に選択決定されるメソッド内容を指す。メッセージは「this参照×第1引数×第2引数..」といった直積集合で考えられているのでシングル、ダブル、マルチプルといった呼称になっている。発送先はthisおよび各引数の派生関係の組み合わせで選択される。thisの派生関係のみ影響しているものは仮想関数と呼ばれるシングルディスパッチになる。それがthisでなく引数ならばただのシングルディスパッチになる。thisまたは各引数の内の2個以上のオブジェクトの派生関係が影響しているものはマルチプルディスパッチになる。その中で特にthisと先頭引数の2個が影響して先頭引数インスタンスの仮想関数がthisを引数にしているVisitor形態のものはダブルディスパッチと呼ばれている。
動的バインディング
dynamic binding)は、識別子が参照するまたは呼び出すオブジェクト、インスタンス、メソッド、データなどのプログラム要素が、コンパイル時ではなく実行時に決められる仕組み全般を指す用語である。識別子はいわゆる変数名や関数名などを指す。
遅延バインディング
late binding)は、識別子が参照するオブジェクトをコンパイル時に決める事前バインディング(early binding)の対義語であり、この場合は識別子が参照するオブジェクトを実行時に決める動的バインディングと同じ意味で用いられる。また他方では動的バインディングの中で、特に実行コードの動的ローディング機能を通して実装される方を遅延バインディングとする考え方もある。実行コードとはDLLやクラスライブラリやモジュールなどを指しており、それらが内包するクラスやメソッドを専用の不透明型または動的束縛型に代入する。その呼び出しのための内部識別子はコンパイル時には存在していないことが多いので、実行時の文字列(char配列やString)を内部識別子に解釈するためのリフレクション機能が多用されることになる。
パッケージ
package)は1個以上のクラスをまとめたものである。多くなったクラスをグループ化するための仕組みである。パッケージの定義は言語ごとに異なるが、名前空間namespace)と同等の機能になっているケースが多い。実装レベルではパッケージ名は自動的にクラス名の接頭辞になってクラス名を差別化し、名前衝突を回避している。
モジュール
module)は1個以上のクラスをまとめたものである。ここでは手続き型構造化プログラミングでのそれではなく、OOP言語で扱われているモジュール概念について説明する。ただしその定義は言語間で様々である。上述のパッケージと同等の機能にしている言語もある。ミックスインのために使われる変数と関数のメンバグループをそれにしてトレイトと同等の機能にしている言語もある。また、クラス群の動的ローディングに焦点を当てたソフトウェアコンポーネント相当の機能にしている言語もある。この動的ローディングは遅延バインディングと同義になり、実行中プロセスへのクラス群の逐次追加を可能にしている。動的ローディング用途のモジュールでは、内包する基底クラスの詳細を明らかにしつつも、その派生クラスの種類と詳細を明らかにしていないケースが多々あるので、その派生クラスを代入するための動的束縛型は特に不透明型(opaque type)と呼ばれる。不透明型はもっぱら型制約と併せて用いられる。
モンキーパッチ
monkey patch)はモジュールやスクリプトファイルなどの動的ローディングを用いて、インタプリタ実行後またはコンパイル後のソースコード内容を変化させる手法である。ソースコードに専用のフィルター処理を記述しておき、その中で任意の箇所を動的ローディングされたモジュール内のクラスや関数や変数で置き換えさせる事で、その時の配置モジュールに合わせた処理内容の変化を起こせる。モジュールを外せば専用のフィルター処理は無効になる。この置き換え(パッチ当て)は遅延バインディング相当である。ソースコードを変えなくてよいのが条件である。
ジェネリクス
generics)は、クラスメンバの任意の「型」を総称化したままのクラス定義を可能にし、そのクラスをインスタンス化する各構文箇所で「型」の詳細を決定できるようにしたコンパイル時の静的な機能である。言語によってはテンプレートtemplate)と呼ばれる。ここでの「型」とはデータの型やメソッドの引数値/返り値/計算値の型を指している。クラス内のそれらを総称化して型変数にし、コンストラクタ呼び出し時の仮型引数に実型引数を適用すると、型変数に実型引数を当てはめたインスタンスが生成される。総称化された型を持つクラスはジェネリッククラスと呼ばれる。特定の型に依存しないクラスを汎用的に定義できるので、型が違うだけの重複コードを削減できるという利点がある。
言語によっては、ジェネリッククラス同士を共変性と反変性による継承関係で結ぶことができる。これはジェネリッククラスに適用する実型引数の継承関係を、そのジェネリッククラス同士の継承関係にシフトする仕組みである。class 猫 extends 動物とするとList<猫>List<動物>のサブクラスになる。共変性は実型引数の継承関係をそのままジェネリッククラスの継承関係にシフトするが、反変性ではこれを逆にする。共変性ではList<猫>List<動物>のサブクラスだが、反変性ではList<動物>List<猫>のサブクラスになる。共変性と反変性はまとめてバリアンス(variance)と呼ばれる事がある。
型制約
type constraint)は、(A)ジェネリッククラスの型引数/型変数、(B)代入値の型が実行時に決められる動的束縛型の変数、(C)動的ローディング時に詳細が隠されたままの値が代入される不透明型の変数、などの宣言に用いられるものである。それぞれは制約用の基準クラスで記号修飾され、その基準クラス及びその派生型の値が代入、束縛、適用されるという宣言になる。(A)の型引数/型変数では基準クラス及びその派生クラスが適用される宣言になる。(B)の動的束縛型では基準クラス及びその派生型の値が代入される宣言になる。(C)の不透明型では基準クラス及びその詳細不明である派生型の値が代入される宣言になる。型制約は型境界(type bound)とも呼ばれる。これには上限と下限がある。型制約と上限型境界(upper type bound)は性質的に同義である。下限型境界(lower type bound)は、基準クラス及びその基底型の値が代入、束縛、適用されるという宣言になる。
タイプメンバ
abstract type member)はジェネリッククラスのメンバ要素であり、ジェネリッククラス同士で型変数の内容をやり取りするための仲介要素である。Aクラスコンストラクタの型引数にBクラスを適用した際に、適切な代入定義が併記されたAクラス内のタイプメンバに、Bクラスがその内部で扱っている総称型もセットで適用できる。連想配列さながらにBクラスがキー的存在になってAクラスのタイプメンバ内容も決定されることから、この仕組みは関連型または連想型(associated type)と呼ばれる。
関数オブジェクト
function object)はクラスベースでは、( )演算子オーバーロードによる実装と、デリゲートによる実装などがある。前者はインスタンスを単に関数名らしく見せるための糖衣構文である。後者のデリゲートは、メソッドシグネチャを型種にした関数ポインタ型の変数である。デリゲート変数にはインスタンスメソッドへの参照が代入されてそのインスタンス種類による処理の多相を表現できる。プロトタイプベースでは、関数はそのままプロパティ/メソッドを自由に付け替えできる(動的バインディング)オブジェクトになる。それらは同時に関数のローカル変数/関数になる。
コルーチン
オブジェクト指向下のイテレータジェネレータは、コルーチン(coroutine)機構に基づいている。通常のサブルーチンがコールする側の復帰アドレスだけをスタックに積むのに対して、コルーチンはコールする側とコールされる側双方の復帰アドレスをスタックに積むというサブルーチン機構である。各要素への作用が記されたオペレータが無名関数やラムダ式などの形態でデータコンテナに渡されると、各要素をフェッチするデータコンテナと、フェッチされた要素を参照ないし加工するオペレータが交互にコールスタックを用いて連携動作を繰り返す。イテレータはデータコンテナの各要素にオペレータを適用してその結果値に置き換えていく機能である。ジェネレータは(A)データコンテナを複製してその複製先の各要素にオペレータを適用していくという更新コンテナ生成機能、(B)オペレータがデータコンテナの各要素を選別していき最後に全選別要素を結合したコンテナを生成する機能、(C)オペレータがデータコンテナを走査して各要素の総和値を生成する機能の三種がある。
メッセージレシーバー
message receiver)は、メソッド名を文字列で受け取ることができる仕組みであり、インスタンスのデフォルトメソッド(共通窓口メソッド)として備えられるものである。メソッド名の次に引数が渡される。メソッド名文字列はセレクタとも呼ばれる。プログラマはセレクタをレシーバー内で自由に解釈して任意のプロセスに選択分岐できる。通常のinstance.method(arg)が、レシーバー機構ではinstance selector: arginstance.receiver(method_name, arg)のようになる。受け取ったセレクタによる選択分岐をシステム側が自動化したものがメソッドになった。これの応用形であるメソッドミッシングは、インスタンスに事前定義されていないメソッドが呼び出された時にのみ、取りこぼし用のレシーバーが呼び出されて、文字列化されたメソッド名と引数が渡されるという仕組みである。
イミュータブル・オブジェクト
immutable object)は、データ不変設定されたクラスのインスタンスを意味する。定数だけを持つインスタンス、不変文字列、不変プリミティブのボックス型、収納内容が不変のコレクション(Array、List、Set、Map)などを指す。イミュータブル(不変)はオブジェクトの性質というよりも、それを何のためにどう扱うかというアルゴリズムとデザインパターンの方が要点になる。不変オブジェクトは並行OOP関数型OOPで最も重要視される。不変オブジェクトではセッターとミューテイタは禁止され、代わりに元への変更を反映して新たに生成したオブジェクトが返されることになる。コレクションクラスでは要素の追加/削除/変更による結果内容のコレクションが新たに生成されてそれが返り値にされまた引数用途にもなることから、これはファーストクラスコレクションと呼ばれる。なお、不変オブジェクトをコピーした専用の可変オブジェクトを取得したのならば、それへのセッターとミューテイタは許される。これはcopy-on-writeと呼ばれる。
デリゲーション
委譲(delegation)。呼び出されたあるクラスのメソッドが自分への引数を他のクラスの同名メソッドにそのまま渡して、その同名メソッドからの返り値をそのまま呼び出し元に渡すという仕組みを指す。委譲先のクラスはhas-a関係で保有されているものになる。委譲先メソッドは必ずしも同名ではなくマッピング名の場合もあり、引数も構成を変えて渡される場合もある。
フォワーディング
転送(forwarding)。委譲先のクラスのメソッドが処理を行わずに、そのまた他のクラスの同名メソッドに引数をそのまま渡して、その返り値をそのまま呼び出し元に渡している場合、冒頭の委譲は転送になる。転送用メソッドではどのクラスに引数をパスするかという選択が行われるので、デリゲーションの多相を表現できる。
サブタイピング
subtyping)はクラス(型)のあらゆる派生関係および派生構造の実装形式とその働き方を包括したプログラム概念である。サブタイプ多相(subtype polymorphism)とも呼ばれる。継承、オーバーライド、コンポジション、ジェネリクス、共変反変バリアンス、不透明型といったものは全てサブタイピングの一側面である。オブジェクト指向でよく使われるものは、振る舞いサブタイピング(behavioral subtyping)であり、継承とメソッドオーバーライドの合わせ技である仮想関数がそれに当たる。
Is-a関係
Is-a)は上位概念と下位概念のコンセプトを扱っており、下位概念is-a上位概念となる。オブジェクト指向ではクラスの継承関係および実装継承関係を意味する用語になっている。これには汎化・特化・実現・実装の四種がある。
  • 汎化(generalization)は、サブクラスからスーパークラスへの連結を指す。
  • 特化(specialization)は、スーパークラスからサブクラスへの連結を指す。
  • 実現(realization)は、クラスからインターフェースへの連結を指す。
  • 実装(implementation)は、インターフェースからクラスへの連結を指す。
Has-a関係
Has-a)は上位集合と部分集合のコンセプトを扱っており、上位集合has-a部分集合となる。オブジェクト指向ではクラスの構成関係を意味する用語になっている。これには合成・集約・収容・依存の四種がある。なお、依存(dependency)はhas-a関係における依存とそれ以外のクラス間関係における依存の意味が異なる二つが存在する。
  • 合成(composition)は強いhas-a関係であり、AクラスがBクラスをデータにし、Aクラスのコンストラクタと同時にBインスタンスが生成され、Aクラスのデストラクタと同時にBインスタンスが破棄される場合、AはBの合成となる。Bが自身のサブクラスで交換される場合は分離とともに破棄される。
  • 集約(aggregation)は弱いhas-a関係であり、AクラスがBクラスをデータにし、Aクラスのコンストラクタとは関係なくBインスタンスが生成され、AクラスのデストラクタでBインスタンスが破棄されず、また分離時も破棄されない場合、AはBの集約となる。Aクラスがコレクション(配列、List、Set、Map)の仕組みでBインスタンスを持つ場合も、AはBの集約となる。
  • 収容(containment)は弱いhas-a関係であり、集約と同じであるが、Aクラスがコレクション(配列、List、Set、Map)の仕組みでBインスタンスを持つ場合のみを指している。コレクション関係を強調する場合、AはBを収容しているとなる。
  • 依存(dependency)は強いhas-a関係であり、Aクラスのいずれかのメソッドが、Bクラスを引数の型または返り値の型にしている場合、AはBに依存しているとなる。なお、AクラスがBクラスの型のデータをhas-aしている場合のAからBへの依存は、合成/集約の方で省略されている。
SOLID原則
SOLID Principles)は、いわゆる抽象化に焦点を当てたクラスの設計原則である。(S)単一責任原則・(O)解放閉鎖原則・(L)リスコフの置換原則・(I)インターフェース分離原則・(D)依存性逆転原則といった五つから成り立っている。1988年にバートランド・メイヤーが提唱した(O)と、1994年にバーバラ・リスコフが提示した(L)に、ソフトウェア技術者ロバート・マーティンが(S)(I)(D)を加えて2000年に発表されている。
  • (S)単一責任原則英語版は、クラスをただ一つの機能を表現するようにデザインすることを推奨している。
  • (O)解放閉鎖原則は、クラスを抽象クラスと実装クラスに分けてデザインすることを推奨している。抽象クラスの定義内容は変更に閉じられており、実装クラスの処理内容は拡張に開かれていることが由来である。
  • (L)リスコフの置換原則は、実装クラスはその抽象クラスに対して振る舞い的に等価計算が可能であることを推奨している。抽象側の公開保有メソッドを実装側も全て保有していれば等価となる。ここでの置換(substitution)とは抽象クラスの型の変数に実装クラスの型のインスタンスを代入できることを意味している。
  • (I)インターフェース分離原則英語版は、一つのクラスから実現される抽象クラスを一つに限定せず、互いに処理内容に影響し合うメソッド群ごとに分離して複数実現することを推奨している。
  • (D)依存性逆転原則は、AクラスがBクラスの機能を使用したい場合は、まずBからその抽象クラスをAに向けて実現し、Aはその抽象クラスを通してBの機能を使用することを推奨している。AはBの機能を使用するという意味でその抽象クラスに依存し、Bは自身の機能を提供するという意味でその抽象クラスに依存することになる。ここでの逆転(inversion)とは実装から抽象への方向性を意味している。
GOFデザインパターン
Gang of Four Design Patterns)はソフトウェア開発において直面しやすい共通的かつ代表的なデザイン問題をピックアップし、それぞれの解決に最適なクラスパターン図を提示したものである。1994年から四人の計算機科学者ないしソフトウェア技術者たち(Gang of Four)によって発表され、OOPのデザインパターンの代表格と見なされた。教科書の内容としても取り上げやすい形式化されたトピックであったためにオブジェクト指向の学習面では非常に重視された。5個の生成パターン、7個の構造パターン、11個の振る舞いパターンに分類されている。
生成に関するパターン
  • Abstract factory
  • Builder
  • Factory Method
  • Prototype
  • Singleton
  • 構造に関するパターン
  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Facade
  • Flyweight
  • Proxy
  • 振る舞いに関するパターン
  • Chain of Responsibility
  • Command
  • Interpreter
  • Iterator
  • Mediator
  • Memento
  • Observer
  • State
  • Strategy
  • Template Method
  • Visitor
  • 脚注

    関連項目