「オブジェクト指向プログラミング」の版間の差分
削除された内容 追加された内容
m →代表的なオブジェクト指向言語: い抜き言葉「やってる」「してる」の使用を回避 |
|||
(同じ利用者による、間の12版が非表示) | |||
1行目:
{{複数の問題
|独自研究=2018年2月
|出典の明記=2019年2月
}}
{{プログラミング言語|index=おふしえくとしこうふろくらみんく}}
[[ファイル:Object oriented design object.jpg|境界|右|フレームなし]]
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)とは、
'''[[オブジェクト指向
== 特徴 ==
現行のオブジェクト指向プログラミングは事実上、1974年に計算機科学者[[バーバラ・リスコフ]]らが提唱した[[抽象データ型]]を基
#[[カプセル化]](''encapsulation'')
#[[継承 (プログラミング)|継承]](''inheritance'')
#[[ポリモーフィズム|多態性]](''polymorphism'')
#[[メッセージ (コンピュータ)|メッセージ
#[[ダイナミックバインディング|遅延バインディング]](''late binding'')
=== カプセル化 ===
一定の関連性を持つデータ(変数、プロパティ)と、それらを操作するコード(関数、プロシージャ)をひとまとめにしてオブジェクトとし、外部に対して必要とされるデータとコードのみを公開し、そ
=== 継承 ===
既存オブジェクトのデータ構成とメソッド構成を引き継いで、新しい派生オブジェクトを定義する仕組みが継承と呼ばれる。引き継ぐ際には新たなデータとメソッドを自由に追加できるので、派生オブジェクトの構成は既存内容+追加内容になる。
=== 多態性 ===
異なる種類のオブジェクトに同一の操作インターフェースを持たせる仕組みが多態性と呼ばれる。オブジェクト指向
=== メッセージ
{{Quotation|''I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages.''
62 ⟶ 61行目:
== 代表的なオブジェクト指向言語 ==
オブジェクト指向言語は、[[抽象データ型]]の型コンストラクタの仕組みに倣った[[クラスベース]]、[[構造体|レコード]]への[[動的束縛|動的バインディング]]の仕組みに倣った[[プロトタイプベース]]、[[Smalltalk]]をルーツにした[[メッセージパッシング|メッセージ]]構文ベースの三タイプに分類されるのが一般的である。[[クラスベース]]では「C++」「Java」「C#」が代表的である。[[プロトタイプベース]]では「Python」「JavaScript」「Ruby」が有名である。[[メッセージパッシング|メッセージ]]構文ベースでは「Smalltalk」「Objective-C」「Self」などがある。言語仕様の中でオブジェクト指向の存在感が比較的高い代表的なプログラミング言語は以下の通りである。
[[ファイル:History of object-oriented programming languages.svg|境界|中央|フレームなし]]
;[[Simula|Simula 67]] 1967年
:1962年に公開された[[Simula]]の後継版であり、[[クラス (コンピュータ)|クラス]]のプログラム概念を導入した最初の言語である。現実世界の擬似モデルを観測するシミュレーション・プログラム制作用に開発されたもので、クラスを
;[[Smalltalk]] 1972年
:[[メッセージパッシング]]のプログラム概念を導入した最初の言語。数値、真偽値、文字列から変数
;[[C++]] 1983年
:[[C言語]]に[[クラスベース]]のオブジェクト指向を追加したもの。Simulaの影響を受けている。[[静的型付け]]の[[クラス (コンピュータ)|クラス]]
;[[Objective-C]] 1984年
:[[C言語]]に[[メッセージパッシング|メッセージ
;[[Object Pascal]] 1986年
:[[Pascal]]にクラスベースのオブジェクト指向を追加したもの。厳格なカプセル化、単一のみの継承、仮想関数と多重実装可な[[インタフェース (抽象型)|インターフェース]]による多態性といった基本に忠実な静的型付け重視である。[[多重定義|関数&演算子オーバーロード]](アドホック多相)と[[ジェネリックプログラミング|ジェネリクス]](パラメトリック多相)は除外された。
;[[Eiffel]] 1986年
:[[Pascal]]にクラスベースのオブジェクト指向を追加した
;[[Self]] 1987年
:[[メッセージパッシング|メッセージ]]構文
;[[CLOS]] 1988年
:[[Common Lisp]]に[[プロトタイプベース]]に似たオブジェクト指向を追加したもの。データオブジェクトとメソッドオブジェクトに分離されており、前者のスロットには任意の変数を、後者のスロットには任意の関数を[[ダイナミックバインディング|動的バインディング]]できる動的型付け重視である。動的型付けのデータオブジェクトを引数にしたメソッドによる[[多重ディスパッチ]]が重視されている。
;[[Python]] 1994年
:[[プロトタイプベース]]と[[クラスベース]]の双方を兼ねたオブジェクト指向スクリプト言語。
;[[Java]] 1995年
:[[C++]]をモデルにしつつ堅牢性とセキュリティを重視した[[クラスベース]]のオブジェクト指向言語。
;[[Delphi]] 1995年
:[[Object Pascal]]を発展させたもの。それと同様にこちらも基本に忠実なクラスベースで静的型付け重視で
;[[Ruby]] 1995年
:[[Python]]を意識して開発されたオブジェクト指向スクリプト言語。日本で誕生してグローバル化したプログラミング言語である。[[Smalltalk]]流のオブジェクト指向を一つの理想にして動的型付けを重視している。
;[[JavaScript]] 1996年
:[[Smalltalk]]の思想を受け継いでデザインされたオブジェクト指向スクリプト言語。当初は[[ウェブアプリケーション|WEBアプリケーション]]開発を主な
;[[C Sharp|C#]] 2000年
:[[Java]]を強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。
;[[Scala]] 2003年
:[[クラスベース]]のオブジェクト指向と[[関数型プログラミング]]を融合させた言語。[[抽象データ型]]と、関数型の[[型システム]]に同等の比重が置かれており静的型付け重視である。パラメトリック多相とサブタイピングを連携させたバリアンスによる多態性が重視されている。型変数の継承関係による[[共変性と反変性 (計算機科学)|共変性と反変性]]で結ばれた[[トレイト]]の実装により[[派生型|派生型付け]]されたオブジェクトは立体的に体系化される。トレイトは多重実装できる。型引数はアドホック多相に該当する型境界で制約されて静的な型チェックをサポートする。[[ジェネリクス]]と[[ミックスイン]]に分類されるトレイトの共存は[[ダックタイピング]]による型識別で実現されている。[[イミュータブル]]なオブジェクト生成と、オブジェクトの[[パターンマッチング]]式の導入も特徴である。
;[[Kotlin]] 2011年
:[[Javaバイトコード]]を出力し、[[Java仮想マシン]]上で動作するJavaテクノロジ
;[[TypeScript]] 2012年
:[[JavaScript]]を強く意識してマイクロソフト社が開発したオブジェクト指向スクリプト言語。
;[[Swift (プログラミング言語)|Swift]] 2014年
:[[Objective-C]]を発展させたものであるが、メッセージ構文は破棄されており、クラスベースのオブジェクト指向になっている。単一継承が採用されているが可視性にプロテクト指定が無いので縦の継承は軽視されている。代わりに[[ミックスイン]]に分類されるプロトコルの多重実装を重視している。プロトコルで特徴付けられる[[インスタンス]]の性質は[[ダックタイピング]]で識別され、コンパイル時と実行時双方の識別を使い分けられる。多態性では動的束縛型(Opaque型)が重視されており、[[静的型付け]]のクラスと[[動的型付け]]の動的束縛型を併用する漸進的型付けの言語と言える。ジェネリクスも導入されている。
== 用語と解説 ==
==== [[クラス (コンピュータ)|クラス]] ====
クラスの仕組みを中心にしたオブジェクト指向を[[クラスベース]]と言う。クラスはデータメンバとメソッドをまとめたものであり、[[プログラム意味論|セマンティクス]]を付加された静的[[構造体|レコード]]とも解釈される。ここでのセマンティクスとはデータの用法を表わすメソッドを指す。クラスはインスタンスのひな型になる。クラスはカプセル化、継承、多態性の三機能を備えていることが求められている。カプセル化はデータメンバとメソッドの可視性を指定する機能である。継承は自身のスーパークラスを指定する機能である。多態性はメソッドの抽象化と[[仮想関数テーブル]]を処理する機能である。コンストラクタとデストラクタの実装も必要とされている。前者はインスタンス生成時に、後者はインスタンス破棄時に呼び出されるメソッドである。
==== プロトタイプオブジェクト ====
プロトタイプの仕組みを中心にしたオブジェクト指向を[[プロトタイプベース]]と言う。プロトタイプベースで言われるオブジェクトとは、中間参照ポインタの動的配列を指す。この動的配列は一般にフレームと呼ばれる。中間参照ポインタは一般にスロットと呼ばれる。スロットにはデータメンバとメソッドの参照が代入されるので、オブジェクトはクラスと同様にデータメンバとメソッドをまとめたものになる。オブジェクトはプロトタイプオブジェクトとオブジェクトに分かれる。前者はクラス、後者はインスタンスに当たるものである。前者はシステム提供プロトタイプとユーザー定義プロトタイプに分かれる。プログラマはシステム提供プロトタイプを派生させてユーザー定義プロトタイプを作成する。プロトタイプには、規定の設計に基づいたデータメンバ参照とメソッド参照が代入されており、オブジェクトのひな型になる。プロトタイプは親プロトタイプ参照用スロットを保持しており、これは継承と類似の機能になる。プロトタイプを複製する形式でオブジェクトは生成される。オブジェクトは複製元プロトタイプと同じデータメンバとメソッドを保持しているが、生成後は任意のデータメンバとメソッドを自由に付け替えできる。これは[[ダイナミックバインディング|動的バインディング]]と呼ばれる。オブジェクトは複製元プロトタイプ参照用スロットを保持している。複製元プロトタイプからその親プロトタイプを辿れる参照のリンクによってオブジェクトは一定の体系化がなされている。
====[[メッセージ (コンピュータ)|メッセージ]]====
オブジェクト指向で言われるメッセージは、複数の方面の考え方が混同されている曖昧な用語になっている。元々はSmalltalkから始まったメッセージ構文ベースのオブジェクト指向の中心機構である。以前はクラスベースの方でもメソッドの呼び出しをメッセージを送るという風に考えることが推奨されていた。メッセージはオブジェクトのコミュニケーションと標榜されているが、その明確な利点はそれほど知られていないのが実情である。最も混同されているものに[[アクターモデル]]があるが、そこで言われる非同期性とオブジェクト指向で言われる評価の遅延性は似て異なるものである。コンポーネント準拠ソフトウェア工学と[[Object Request Broker|オブジェクトリクエストブローカー]]で言われる[[ソフトウェアコンポーネント]]同士の通信もメッセージパッシングと呼ばれることが多いが、その仕様と機能は動的ディスパッチに該当するものである。メッセージのオブジェクト指向的運用はメッセージングと名付けられている。その具体的な機能例は、Smalltalk、Objective-C、Selfの[[メッセージ転送|メッセージレシーバー]]と、Rubyのメソッドミッシングであるが、いずれもメッセージングの本質ではないとも言われている。
====
クラスベースではクラスを実体化したものであり、実装レベルで言うとデータメンバと仮想関数テーブルをメモリ上に展開したものになる。プロトタイプベースではプロトタイプオブジェクトのクローンで生成されたオブジェクトを指す。実装レベルで言うとメモリ上に展開された中間参照ポインタの動的配列になる。
====[[フィールド (計算機科学)|データメンバ]]====
クラスまたはオブジェクトに属する変数。言語によってフィールド、プロパティ、メンバ変数と呼ばれる。データメンバは、クラスデータメンバとインスタンスデータメンバに分かれる。クラスデータメンバは静的データメンバとも呼ばれる。その中で定数化されたものはクラス[[定数 (プログラミング)|定数]]と呼ばれる。クラスデータメンバはクラス名の名前空間でスコープされたグローバル変数と同じものであり、プログラム開始時から終了時まで確保される。インスタンスデータメンバはインスタンス生成時にメモリ上に確保されるものであり、その破棄時に消滅する。プロトタイプベースではプロトタイプオブジェクトが保持する特定のデータメンバが静的データメンバに該当するものになる。
==== [[メソッド (計算機科学)|メソッド]] ====
クラスまたはオブジェクトに属する関数。言語によってはメンバ関数とも呼ばれる。メソッドは、クラスメソッドとインスタンスメソッドに分かれる。クラスメソッドは静的メソッドとも呼ばれる。クラスメソッドはクラス名の名前空間でスコープされたグローバル関数と同じものである。インスタンスメソッドを呼び出すには、そのメソッドが属するインスタンス参照が必要になる。これはthisインスタンスと呼ばれる。プロトタイプベースではプロトタイプオブジェクトが保持する特定のメソッドが静的メソッドに該当するものになる。
==== [[コンストラクタ]]====
インスタンス生成時に呼び出されるそのクラスのメソッドである。インスタンスデータメンバを任意の値で初期化するためのものであるが、その他の初期化コードも記述できる。プロトタイプベースではプロトタイプオブジェクトと同名のグローバル関数として存在している。
==== [[デストラクタ]] ====
インスタンス破棄時に呼び出されるそのクラスのメソッドである。インスタンス破棄の影響を解決する任意の後始末コードを記述できる。インスタンスの破棄は占有メモリの解放を意味する。なお、ガーベジコレクタ実装言語ではファイナライザになっている事がある。プログラマが呼び出すデストラクタの方はその終了がメモリ解放に直結してるのに対し、ガーベジコレクタが呼び出すファイナライザの方はそうではない。
====
カプセル化に基づくデータメンバとメソッドの可視性を決定するものである。可視性はプライベート、プロテクト、パブリックの三種が基本である。プライベートは同クラス内のみ、プロテクトは同クラス内と派生クラス内のみ、パブリックはどこからでもアクセス可能である。
==== [[インタフェース (抽象型)|インターフェース]] ====
プログラム概念と機能名の双方を指す用語である。言語によってはプロトコルと言われる。抽象メソッドと具象メソッド(実装内容付き)で構成される純粋~半抽象クラスを意味する。クラスの振る舞い局面を抽出したものであり、[[統一モデリング言語|UML]]では実現と言われる。クラスによるインターフェースの継承は実装と呼ばれる。多重実装可が普通である。ミックスインとの違いは、抽象階層に焦点が当てられている事であり、直下の実装オブジェクトを共通の振る舞い局面でまとめることがその役割である。インターフェースは自身の実装オブジェクトをグループ化できる。{{仮リンク|指名的型付け|en|Nominal type system|label=}}に準拠しているのでインターフェース名という文脈自体が振る舞い局面の識別基準になる。インターフェースは抽象メソッド主体なので多重継承時のメンバ名の重複はあまり問題にならない。共通の実装メソッドに集約されるからである。インターフェースはインスタンス化されない。
==== [[ミックスイン]] ====
インターフェースに似たプログラム概念を指す用語である。機能名は言語によって[[トレイト]]またはプロトコルと言われる。抽象&具象メソッドとデータメンバで構成される継承専用クラスを意味する。クラスを特徴付けるための装飾部品である。クラスによるトレイトの継承は実装と呼ばれる。多重実装可が普通である。インターフェースとの違いは、トレイトの実装階層に焦点が当てられている事であり、オブジェクトを所有メンバで特定してまとめることがその役割である。トレイトは自身の[[上位集合]]であるオブジェクトをグループ化できる。{{仮リンク|構造的型付け|en|Structural type system|label=}}に準拠しているので所属メンバ構成自体がトレイト等価性の識別基準になる。これはトレイト実装を明記してなくても、そのトレイトが内包する全メンバを所持していれば同じトレイトと見なされることを意味する。トレイトは多重継承時のメンバ名重複の際にその参照の優先順位に注意する必要が出てくる。トレイトはインスタンス化されない。
====[[メタクラス]]====
(''metaclass'')とはクラスを定義しているクラスであるが、その実態はシステム側が用意している特別なシングルトンオブジェクトと考えた方が分かりやすい。システム内のクラス定義情報をクラスに見立てて、それをインスタンス化したものである。慣例的にこれをメタクラスと呼ぶ。メタクラスはクラスのデータメンバとメソッドの定義情報を指し、それを操作する機能はリフレクションと呼ばれる。クラスベースで用いられるものである。
==== [[リフレクション (情報工学)|リフレクション]] ====
(''reflection'')はクラスの定義情報を変更する機能であるが、言語ごとに変更できる定義情報の範囲は異なっている。データメンバではデータ型、識別子、可視性が変更対象になる。メソッドではリターン型、識別子、パラメータリスト、可視性、仮想指定が変更対象になる。双方の追加定義と削除もできる事がある。スーパークラスも変更できる事がある。また、実行時の文字列(char配列やString)をデータメンバとメソッドの識別子として解釈できる機能もリフレクションに当たる。これは実行時の文字列によるデータメンバの参照とメソッドの呼び出しを可能にする。
==== 遅延バインディング ====
(''late binding'')はやや[[ランタイム環境]]寄りのプログラム概念であり、リフレクション機能を通して実装される。抽象化された型に対して、実行時の文字列(char配列やString)を内部識別子に解釈し、コンパイル時には認識されていなかったオブジェクトをローディングして代入する流れを指す。オブジェクトの呼び出しが、[[ダイナミックリンクライブラリ|DLL]]やクラスライブラリの動的ローディングに繋がることが遅延バインディングと呼ばれる基準になる。[[ストアドプロシージャ]]の動的ロード、代入、呼び出しもそれに当たる。ローディング基準が外される例では、プログラム内でデータとして扱われている[[コードブロック]]を関数の型に代入して呼び出すという仕組みがある。そのコードブロックは文字値と数値の混合配列であり、リフレクション機能を利用して実行する。
====
(''dynamic dispatch'')はメソッドの呼び出しを受けるオブジェクトの側に焦点を当てたプログラム概念である。一般的なローカルメソッドでは、識別子にマッピングされている実行時の参照が指すメソッド実体を呼び出す仕組みを意味する。参照が指す先はプログラム実行中に随時変更されるのでコンパイル時には当然特定できない。この参照の変更は動的バインディングと呼ばれる。リモートメソッドでは、受け取ったバイトデータ列を解釈しリフレクション機能でメソッドを呼び出す仕組みを意味する。受信側の実行時状態による選択が加えられる事もある。始めのアクセスで所有メソッドリストを呼び出し側に送り、無駄なエラーリクエストを無くす仕組みと併用される事が多い。
== 脚注 ==
199 ⟶ 153行目:
== 関連項目 ==
{{Wikibooks|オブジェクト指向|オブジェクト指向}}
* [[オブジェクト指向]]
* [[クラス (コンピュータ)]]
* [[メッセージ (コンピュータ)]]
* [[インスタンス]]
* [[フィールド (計算機科学)]]
* [[メソッド (計算機科学)]]
* [[インスタンス変数]]
* [[クラス変数]]
* [[カプセル化]]
* [[継承 (プログラミング)|継承]]
* [[多態性]]
* [[委譲]]
{{Normdaten}}
|