「オブジェクト指向プログラミング」の版間の差分
削除された内容 追加された内容
編集の要約なし |
Goldensundown2 (会話 | 投稿記録) |
||
(同じ利用者による、間の24版が非表示) | |||
1行目:
{{プログラミング言語|index=おふしえくとしこうふろくらみんく}}
[[ファイル:History of object-oriented programming languages.svg|サムネイル|OOP言語の系譜(水色がOOP)|代替文=|280x280ピクセル]]
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}
OOPの成り立ちにもまた諸説ある。オブジェクト指向プログラミングという言葉自体は、計算機科学者[[アラン・ケイ]]が1972年に[[Smalltalk]]の言語設計を説明する中で初めて生み出されている。なお、データとコードの複合体である[[オブジェクト (プログラミング)|オブジェクト]]という用語を確立したのは1967年公開の[[Simula|Simula67]]であった。[[Simula|Simula67]]の[[クラス (コンピュータ)|クラス]]と[[オブジェクト (プログラミング)|オブジェクト]]の設計及び用法は[[手続き型プログラミング]]の機能拡張に近いものであったが、こちらもOOPの草分けと見なされるようになった。[[Smalltalk]]のプログラム内のあらゆる要素をオブジェクトとして扱い、[[メッセージパッシング]]で相互作用させる本来の意味でのオブジェクト指向設計は、哲学的かつ理論偏重のきらいがあったので実践面ではさほど広まらなかった。1983年に公開された[[C++]]が契機となり、OOPはまた違った角度から注目されるようになった。最終的にこの[[C++]]の設計スタイルが物議を醸しながらもOOPの主流となるに到り、同時にOOPの三大原則とされる[[カプセル化]]、[[継承 (プログラミング)|継承]]、[[ポリモーフィズム|多態性]]の[[プログラミングパラダイム]]が確立されている。
== 特徴 ==
プログラミングパラダイムとしてのオブジェクト指向の確立は紆余曲折を経ており(後述)その詳細の解釈も様々であるが、一定の枠組みとなる三つの原則仕様(''fundamental principle'')が存在する。この三原則に従った言語仕様を総体的または部分的に備えたプログラミング言語がオブジェクト指向準拠と判別される。1~3はいわゆるOOPの三大原則とされるものであり、[[C++]]を契機にして確立された。4はオブジェクト指向プログラミングという用語の発端となった[[Smalltalk]]設計の主軸であるが、現在では亜流となっている。
#[[カプセル化]]
#[[継承 (プログラミング)|継承]]
#[[ポリモーフィズム|多態性]]
#*アドホック多態性(''ad hoc polymorphism'')
#**[[多重定義|関数オーバーロード]](''function overloading'')
#**[[多重定義|演算子オーバーロード]](''operator overloading'')
#*パラメータ多態性(''parameter polymorphism'')
#*[[仮想関数]] (''virtual function'')▼
#**[[ジェネリックプログラミング|ジェネリック関数]](''generic function'')
#*[[多重ディスパッチ]] (''multiple dispatch'')▼
#**[[
#*[[派生型|サブタイプ多態性]](''subtyping'')
#**動的ディスパッチ(''dynamic dispatch'')
#**[[ダブルディスパッチ]](''double dispatch'')
#[[メッセージ (コンピュータ)|メッセージパッシング]](''message passing'')
; カプセル化
従来の
; 継承
; 多態性
アドホック多態性は単にソースコードの記述を一部自動化するものである。'''関数オーバーロード'''は引数の並び方によって同じ名前のメソッドをコンパイル時に自動的に差別化する機能である。'''演算子オーバーロード'''は、扱う数値の型に従って宣言された演算記号を関数名と見なすようにし、単項演算子なら右の数値を第一引数とし、二項演算子なら左右の数値をそれぞれ第一第二引数として関数呼び出しのコードが生成されるという仕組みだった。これらは静的な多態性とされる。
パラメータ多態性もソースコードの記述を一部自動化するものである。関数内またはクラス内の型指定部分をワイルドカードにして宣言しておき、ソースコード内で関数またはクラスが実装記述されると、その具体的な型指定を関数内またはクラス内のワイルドカードに当てはめたコード部分がコンパイル時に自動生成されるという機能だった。前者は'''ジェネリック関数'''と呼ばれ、後者はより広い範囲を扱う事から'''ジェネリックプログラミング'''と名付けられた。これらも静的な多態性に位置付けられている。
サブタイプ多態性は動的なものである。最も初期のOOPであるSimula67は、シミュレーション内で扱う多種多様なオブジェクトを継承によって体系化したが、コード部分の細かな違いは共通スーパークラスに属する共通プロシージャ内の分岐フローで処理していた。サブクラスの数だけ分岐構文が増える頻雑さを解消する為に、共通プロシージャをただの住所テーブルにしてサブクラスの実装時に同名プロシージャのアドレスを収納させ、呼び出し時はそのアドレスへジャンプするという機能が考案され、これが'''仮想関数'''となった。'''動的ディスパッチ'''はSmalltalkのオブジェクト設計に由来するものであり、その実装の仕方は様々でやや曖昧な仕様でもある。メッセージを受け取ったレシーバーがオブジェクト内部で動的な状態に従い動的な処理を行って結果を返すというランタイム環境上のプロセスが後に動的ディスパッチのカテゴリで括られた。遠隔プロセスを扱うリモートメソッドのシステムも動的ディスパッチに該当するものである。'''多重ディスパッチ'''は動的な関数オーバーロードに近いものである。関数コール時または関数ブロック内で、それぞれの引数が動的に型審査されて型変化(''dynamic casting'')された後に、その引数パターンに対応した同名関数または分岐ルーチンに処理が移行されるという動的変化プロセスを指した。'''ダブルディスパッチ'''は多重ディスパッチの亜流またはその派生物であり、二通りの考え方がある。動的型審査および型変化されるBオブジェクトを単一引数にしてAオブジェクトの仮想関数メソッドを呼び出す形態と、多重ディスパッチに用いる引数を二つに限定した形態である。いずれも実行時状態に応じた動的変化プロセスとなった。これは主にデータ集合を対象にして分類、解析、作用といった処理を連続的または再帰的に行うアルゴリズムで用いられた。
; メッセージパッシング
Smalltalkの影響を受けた後継言語においても、あらゆるプログラム要素をメッセージで表現しようとする理論の追求は避けられ、例えば制御フローは制御構文で扱われている。またメッセージングに対する認識もシフトし、オブジェクトの代表となるメソッドがパラメータを受け取り多様な処理と移譲を行ういわゆるレシーバーの仕組み自体がメッセージングそのものと見なされるようになった。そのメカニズムを応用したリモートメソッドを実現するバイトデータの送受信もメッセージパッシングの代表例となった。この様にメッセージパッシング設計の本質は見失われながらも、その側面的仕様は数々のOOP言語に導入されてもいる。
== 歴史 ==
58 ⟶ 65行目:
== OOP言語一覧 ==
オブジェクト指向を総体的または部分的にサポートする機能を備えたプログラミング言語の公開は、1980年代後半から顕著となった。
[[Simula|'''Simula 67''']] 1967年
: 1962年に公開された[[Simula]]の後継版であり、[[クラス (コンピュータ)|クラス
'''[[Smalltalk]]'''
:
'''[[C++]]''' 1983年
: [[C言語]]に
'''[[Objective-C]]''' 1984年
:[[C言語]]
'''[[Object Pascal]]''' 1986年
:[[Pascal]]
'''[[Eiffel]]''' 1986年
:[[Pascal]]をベースにして
'''[[Self]]''' 1987年
: メッセージ
'''[[CLOS]]''' 1988年
:[[Common Lisp]]
'''[[Python]]''' 1990年
:
'''[[Java]]''' 1995年
:堅牢性と安全性を重視した
'''[[Delphi]]''' 1995年
:
'''[[Ruby]]''' 1995年
:
'''[[JavaScript]]''' 1996年
:[[ウェブアプリケーション]]開発を主な目的とするOOPスクリプト言語。主に[[プロトタイプベース]]でオブジェクトを扱う事でコーディングを簡便にしてい
[[C Sharp|'''C#''']] 2000年
:[[Java]]を強く意識して開発された
[[Microsoft Visual Basic .NET|'''Visual Basic.NET''']] 2002年
:
'''[[Ceylon]]''' 2011年
:[[Java]]を元に開発され、その長所と短所を見直しつつ再設計されたOOP言語。Javaの改造版である。また[[JavaScript]]にもコンバートできる。
[[Swift (プログラミング言語)|'''Swift''']] 2014年
:高度に整えられたマルチパラダイムプログラミング言語。クラスのメカニズムをベースにしたオブジェクト指向的言語仕様も導入されている。
== OOP言語の仕組み ==
130 ⟶ 133行目:
これらをどのように言語の要素として提供し、どのような[[機械語]]コードで実現するかによって様々な[[オブジェクト指向プログラミング言語]]のバリエーションが生まれる。以下、オブジェクト指向プログラミング言語が提供する様々な要素が上記の仕組みをどのように実現しているかについて概観する。
=== オブジェクトの概念と実
'''[[オブジェクト (プログラミング)|オブジェクト]]''' ({{Lang|en|object}}) はオブジェクト指向プログラミングの中心となる'''概念'''であり、この概念を'''実際'''にどう実現するかは[[オブジェクト指向プログラミング言語]]により異なる。
139 ⟶ 142行目:
* 概念的には コードとデータが一つになっている。
==== オブジェクト
実際のプログラムでは、全てのオブジェクトが互いに全く異なった存在ではなくオブジェクトは種類に分けることが出来る。
154 ⟶ 157行目:
もう一つは同一種類のオブジェクトでもそれぞれ異なる部分、典型的には各オブジェクトが保持するデータ群である。
==== クラスのオブジェクト化 ====
動的型付けを採用するオブジェクト指向言語の多くは、クラスより生成するインスタンスの他に[[メタクラス]]という機能を持ちクラス自体をオブジェクトとして扱うことが出来る。このためオブジェクトには、インスタンスオブジェクトとクラスオブジェクトという2種類のオブジェクトが存在する。Java等クラスオブジェクトを持たない言語の文化圏では、インスタンスオブジェクトとオブジェクトを混同して説明される事があるが、Objective-CやPython、Ruby等、インスタンスオブジェクトとクラスオブジェクトが別であるオブジェクト指向言語では区別して説明される。<ref>Objective-Cプログラミ
ング言語[https://developer.apple.com/jp/devcenter/ios/library/documentation/ObjC.pdf]</ref>
160 ⟶ 163行目:
<ref>クラス/メソッドの定義 (Ruby manual) [http://www.ruby-lang.org/ja/old-man/html/_A5AFA5E9A5B9A1BFA5E1A5BDA5C3A5C9A4CEC4EAB5C1.html]</ref>元々はSmalltalkから始まった用語である。
====
{{seealso|this (プログラミング)}}
そしてあるオブジェクトOにメッセージを配送し適切なメッセージ処理コード(振る舞い)を呼び出す際には、まず対象となるオブジェクトOについて共通部分の格納場所を見つけて適切なコードを選び出し、次にそのコードに対して処理対象となるオブジェクトO固有のデータの所在を示す'''オブジェクトID'''を渡すようになっている。
179 ⟶ 182行目:
最も普及している[[クラスベース]]の言語では、共通部分はオブジェクトの種類を表現するクラスに保持され、各オブジェクトは固有データと共にそのクラスのIDを保持する。そしてオブジェクトに送られるメッセージはその送り先オブジェクトにあるクラスのIDからクラスを見つけ、その中からメッセージを処理するコードを見つけ出し、処理対象となっているオブジェクトのIDを付してそのコードを呼び出す仕組みになっている。
==== コンポジション ====
'''コンポジション'''は、複数のオブジェクトがある一つのオブジェクトの構成要素となっている巨大なオブジェクト群をいう。コンポジションのもとにあるオブジェクトは同一の生存期間を持ち、一つの巨大な仮想オブジェクトの構成部品として機能する。▼
=== メッセージ ===
207 ⟶ 213行目:
多くの言語でクラスは言語の要素として直接実現されているが、これは実行効率のためであり、そのように実現することが必須というわけではない。実際、各クラスをそれぞれオブジェクトとして提供する言語も存在する(例:[[Smalltalk]])。このような言語ではある種の'''[[リフレクション (情報工学)|リフレクション]]''' (reflection) が可能となる。即ち必要があればプログラムで実行時にクラスの動作を変更することが可能である。これは非常に大きな柔軟性を提供するが、[[処理系|言語処理系]]による最適化が難しいため実行効率は低下することが多い。{{いつ範囲|date=2019年2月|近年}}では柔軟性と効率性を両立させるために基本的に言語要素としてクラスを提供した上で、リフレクション機能が必要なプログラムに対しては必要に応じて各クラスに対応するクラス・オブジェクトをプログラムが獲得できるようにしている言語が現れてきている。(例:JavaのリフレクションAPI)
====
{{main|プロトタイプベース}}
クラスは非常に多くのオブジェクト指向プログラミング言語で提供されている機能ではあるが、オブジェクト指向プログラミング言語に必須の機能というわけではない。実際にオブジェクトの管理や、データ・メンバや[[メソッド (計算機科学)|メソッド]]の記述、[[継承 (プログラミング)|継承]]に際してクラスという仕組みに依存せずに、もしくはクラスという仕組み自体を持たずに別の手段でこれらを実現している言語も存在する。このような言語を'''[[プロトタイプベース|インスタンスベース]]''' (''{{Lang|en|instance-based}}'')、'''オブジェクトベース''' (''object-based'') あるいは'''プロトタイプベース''' (''{{Lang|en|prototype-based}}'') のオブジェクト指向プログラミング言語と呼ぶ。インスタンスベースまたはそれに類するオブジェクト指向プログラミング言語には以下のようなものがある:
245 ⟶ 251行目:
'''[[メソッド (計算機科学)|メソッド]]''' ({{Lang|en|method}}) は特定の種類のメッセージの処理方法を記述したものである。メソッドも[[メソッド (計算機科学)#インスタンスメソッド|インスタンス・メソッド]]と[[メソッド (計算機科学)#静的メソッド|クラス・メソッド]]の2種にできる。インスタンス・メソッドはそのクラスの各インスタンスオブジェクトを操作し、クラス・メソッドはクラスオブジェクトを操作する。メソッドとの集まりはそのクラスのオブジェクトが処理可能なメッセージのカタログの機能を果たす。
一例として、[[C++]]では、メソッドは'''メンバ関数''' ({{Lang|en|member function}}) や'''関数メンバ''' (function member) と呼ばれる。これはC++が[[グローバル関数]]との区別をつけることと、クラスを[[抽象データ型]]の拡張と位置づけ、非メッセージメタファな言語思想を持っている為である。これら言語ではメソッドをオブジェクト(=クラスやインスタンス)の持ち物として捉えず、クラスに定義された機能要素であると考える。メッセージメタファを否定するため、同時にメッセージを実行するメソッド(手法)ではありえない。▼
▲[[C++]]ではメソッドは'''メンバ関数''' ({{Lang|en|member function}}) や'''関数メンバ''' (function member) と呼ばれる。これはC++が[[グローバル関数]]との区別をつけることと、クラスを[[抽象データ型]]の拡張と位置づけ、非メッセージメタファな言語思想を持っている為である。これら言語ではメソッドをオブジェクト(=クラスやインスタンス)の持ち物として捉えず、クラスに定義された機能要素であると考える。メッセージメタファを否定するため、同時にメッセージを実行するメソッド(手法)ではありえない。
==== クラスメソッド ====
279 ⟶ 284行目:
C++やJavaなどでは、コンストラクタはクラスと同じ名前を持ち、戻り値を持たないメソッドとして定義される。C++では一部のコンストラクタは[[型変換演算子]]として、また[[暗黙の型変換]]にも利用される。
=== ガベージコレ
オブジェクト指向プログラミング言語では、オブジェクトへの[[参照 (情報工学)|参照]]や[[ポインタ (プログラミング)|ポインタ]]が多用される。そのため、オブジェクトの[[メモリ]]への割り当てと破棄に関して、[[ガベージコレクション]]による自動管理機能を備えているものが多い。ただし、すべての言語が備えているわけではない。例えば、C++はガベージコレクションを備えていない。
=== アクセス
オブジェクト指向プログラミングにおいて、[[オブジェクト (プログラミング)|オブジェクト]]は、[[カプセル化]]されておりブラックボックスである。したがって、処理するメッセージのカタログ、つまりインタフェースだけが利用者に公開され、内部の詳細は隠されるのが基本である。しかし、あるクラスのインスタンスの内部だけで利用されるメソッドまで公開してしまうと、利用者にとって煩雑である。また、定数データ・メンバのようなものは一々メソッドでアクセスするようにせず公開してしまっても、カプセル化の利点は失われず効率的でもある。そこで、オブジェクトを定義するプログラマが各データ・メンバやメソッドについて公開・非公開を設定できる機能を用意している言語は多い。
291 ⟶ 296行目:
なお、public、private、protectedというキーワードは、多くのプログラミング言語で用いられているが、その示す意味は言語ごとに差異があるため、注意が必要である。
===
▲'''コンポジション'''は、複数のオブジェクトがある一つのオブジェクトの構成要素となっている巨大なオブジェクト群をいう。コンポジションのもとにあるオブジェクトは同一の生存期間を持ち、一つの巨大な仮想オブジェクトの構成部品として機能する。
{{脚注ヘルプ}}
{{Reflist}}
|