Web Analytics
Privacy Policy Cookie Policy Terms and Conditions オブジェクト指向プログラミング - Wikipedia

オブジェクト指向プログラミング

出典: フリー百科事典『ウィキペディア(Wikipedia)』

オブジェクト指向プログラミング (object-oriented programming, OOP) とは相互にメッセージ (message) を送りあうオブジェクト (object) の集まりとしてプログラムを構成する技法である。この技法をサポートするプログラミング言語オブジェクト指向言語 (object-oriented programming language, OOPL) と呼ばれる。オブジェクト指向プログラミングには必ずしもオブジェクト指向言語を用いる必要は無いが、オブジェクト指向言語の備えるクラスとその継承などの仕組みを利用するほうが格段に開発効率は向上する。

以上のようなオブジェクト指向プログラミング技法の普及と発達に関連して次の3つのものらが発達した。

これらオブジェクトを中心とした様々な枠組みを総称してオブジェクト指向とも言う。

目次

[編集] 概説

オブジェクト指向プログラミングとは、オブジェクト指向に沿ってプログラミングすることである。それ以外の意味はない。

しかしただ、対となるオブジェクト指向の記事ではオブジェクト指向プログラミングについての補足に十分ではないことから、この記事内で次の2点について混在させながら説明する。

  • オブジェクト指向を理解する。
  • そのオブジェクト指向というアイデアに沿うために どうプログラムで実現するか。

(この記事の本意としては後者を指す)

[編集] オブジェクト指向

「データをどう操作するか」といった管理者としての見方ではなく、「今向かっている1つ1つの対象が何をするものなのか」について目を向けさせた。このように今向かっている対象を明らかにしていくことでオブジェクト同士が関連して動きあい出すので、どう組むかという問題の解決にもなる。


[編集] 主な用語の一覧

(この節は書きかけであり、正確でないかもしれません) この節では、本文全体の位置関係を案内する見通しの観点から、要点の見出しを一覧する目次に留めます。

オブジェクト (object)
自身を操作するコードを内蔵するデータ構造。何をすることができるか(=振る舞い)を公開する。
メッセージ (message)
何を実現したいか結果を説明したもの。オブジェクトに対してメッセージを投げかけると何らかの振る舞いをする。また、結果を遂行するに足るデータ。
振る舞い (behavior)
オブジェクトが実現できる結果(働き)。これを必須のものと課すと責任(responsibility)と呼ぶ。
責任 (responsibility)
オブジェクトに課せられる、実現しなければならない結果(働き)。その方法は定めず任せられる。
メソッド (method)
どう実現するか。(振る舞いと比較すると)メソッドは、振る舞いの実現方法、外からは見えない段取りを指す。
カプセル化、情報隠蔽(encapsulate)
オブジェクトは どのようなデータを持っているかについては隠蔽し、どのようなメッセージを受け取るかだけを公開する。
インターフェース(interface)
利用者には振る舞い(受け取り可能なメッセージ)を公開し実現方法を隠す。提供者には責任(受け取らなければならないメッセージ)を明示し利用者が何であるかを隠す。
ポリモーフィズム(多態性、多様性)
抽象的なオブジェクトを扱うコードは、具体的な多種多様のオブジェクトも扱える。
インヘリタンス(継承)
継承したオブジェクト(具体的なオブジェクト)は、継承元のオブジェクト(抽象的なオブジェクト)と同じくメッセージに対応できる。
オーバーライド
継承したオブジェクト(具体的なオブジェクト)に、継承元のオブジェクト(抽象的なオブジェクト)とは部分ごとに異なる振る舞いをさせること。
インスタンス
同じ振る舞いをし、データ内容が別個の実在である1つ1つのオブジェクト。

次は、必須ではないもののオブジェクト指向プログラミングと関連のあるもの。

クラス
振る舞いを規定する。継承したクラスでは オーバーライドしたり、新たな振る舞いを追加することができる。

[編集] オブジェクト指向が意図的に意識しないようにしている事柄

(この節は書きかけであり、正確でないかもしれません) この節では、オブジェクト指向プログラミングが オブジェクト指向プログラミング以前よりも高級言語(コンピューターの物理的構造よりも、扱う対象を概念で取り扱う)に移っていることを表します。

  • 構造体、共用体、変数 …オブジェクトとして捉えなおす。
  • メモリ、メモリアドレス …意識しない。
  • 代入 …代入の替わりとなるメッセージを投げかける行為として捉えなおす。
  • 0や他の数値を用いて条件の真偽を表す規則 …true、falseの2値の真偽を持つ論理型を使う。

[編集] 本題に入る前に 注意点について

(この節は書きかけです。記事の構成の見直しを進めるために分割した便宜的な分類です)

オブジェクト指向プログラミングについて、よく生じる早合点、誤解に対して念を押すべく 次のようなことがよく注意説明されることがある。
オブジェクト指向であるプログラミング言語を十分に使いこなせるようになることと、オブジェクト指向プログラミングを理解することとは、別の話である。
これは一般的な話ではあるが、例えば Java言語やC#言語を想定すると次のように言える。
言語に用意されているクラス、継承といったオブジェクト指向を実装するための機構を用いて書かれているからといって、即 それがオブジェクト指向に沿っているか? といえば、必ずしもそうではない。

もちろん、プログラム言語とオブジェクト指向プログラミングの両方に精通していることが望ましい。

あくまで オブジェクト指向を目指し 実現するためには、オブジェクト指向でないプログラム言語を利用するよりは、オブジェクト指向であるプログラミング言語を利用する方が 都合がよいということに過ぎない。その際、プログラミング言語特有の実装、表記方法で オブジェクト指向プログラミングの説明がされやすく、区別があいまいになりやすい。そこで記事の本題では、オブジェクト指向プログラミングについては概念として説明し、オブジェクト指向であるプログラミング言語については実際にはと称して説明する。

プログラムを習得しようとする際、「正しくプログラムが動いた」というブラックボックスの発想が1つの目標として目指される。オブジェクト指向プログラミングでは これとは別に、「オブジェクト指向になっている」という発想も加えた両方が必要である。後者の判定は、自動的に行われるものではなく人間の作業となる。

[編集] 特徴

(この節は書きかけです)

[編集] カプセル化

カプセル化は情報隠蔽とも呼ばれる。データにアクセスする方法を制限し、安全性などいくつかの目標を高めること。詳しくはリンク先を参照。内部が隠れることを強調し過ぎるとブラックボックスという別概念(アウトプットを重視している)になってしまい、安全性など重視すべきいくつかの目的からずれる。

[編集] オブジェクト

オブジェクトは、データを持たせ そのデータをオブジェクト自身に扱わせる方法(メソッド)も組み込ませたというものである。

例えば、野球のビデオゲームを作りたいとする。野球場には選手やボール、バットがある。 選手やボール、バットはエンティティー(模倣したい対象)である。 パソコンの機体の蓋を開けて 箱の中へ選手に入ってもらったり、ボールを入れたとしても、 ビデオゲームの画面中に登場するわけではない。 ビデオゲーム中に登場するためには、選手データやボール画像といった素材として用意しなければならない。 オブジェクト指向プログラミングでは、ビデオゲームに限らずソフトウェア全般について言えることだが、 エンティティーをコンピューター内で表現する仕組みとしてオブジェクトを設定するといったことをする。

例えば投手であれば 関節の柔軟性や足腰の強さといったデータ、 そして「投げる」という振る舞いに対して組み込まれる制球の乱れや球速の算出方法(メソッド)など、 ビデオゲーム的な遊びを持たせたオブジェクトとして設定するといったことが考えられる。 打者であれば 動体視力や体の大きさといったデータ、 そして「打つ」といった振る舞いに対しては 初球から手を出すといった癖やバットスピードなど打席での行動の算出方法(メソッド)など、 ビデオゲーム的な遊びを持たせたオブジェクトとして設定するといったことが考えられる。

ここでは投手と打者という例を挙げたが、オブジェクトの用途は物体を表現するだけには留まらない。 オブジェクトは、個のものとしてデータを持たされ、その個自身のデータを個自身の判断で扱うメソッドも組み込まれた、その個を指すあらゆるものである。 オブジェクトについて上記のように特徴は説明できるが、何を個として洗い出すかは設計者が判断する。

例を挙げる。

  • 「物」はオブジェクトとして捉えやすい。(時計など)
  • 「日付」もオブジェクトにできる。日付に日数を足すといった操作を組み込んでおくと便利である。
  • 「リスト」もオブジェクトにできる。これはモデルと呼ばれることもある。(この仲間ではテーブル表やツリー構造など)
  • 「グループ」もオブジェクトとして扱うことができる。(赤組白組といった選手のまとまりや、ラジオボタンのグループなど)
  • 「状態」もオブジェクトにすることができる。(運転中、停止中など状態遷移の一状態)
  • 「思考パターンA」「思考パターンB」といったアルゴリズムもオブジェクトとして用意することができる。
  • 画面上の「アイコン」もオブジェクトとして作ることができるように、アイコンを区切る「区切り」(separator)もオブジェクトとしている場合もある。
  • 何かの「一部分」もオブジェクトとして捉えることができる。動物の体の中での「頭部」など。

データのまとまりとして捉えることができ、その操作もデータ自体に持たせておいた方が都合が良いと設計者が判断するようなものは、 オブジェクト指向プログラミングの中では オブジェクトとして用意できるのである。

[編集] カプセル化の方法

(この節は書きかけです)

意図しないデータの変更を防ぐために、データが在るかどうかも隠蔽し、例えば外部からのアクセスに対して 許す振る舞いだけを公開(例えばpublic指定)するといった、アクセス制限を設ける方法が用いられる。この際、振る舞いの実装も隠蔽され、宣言だけ公開される。

この際には、次の2つの立場、または視点に分離される。

  • 利用者(何ができるかを知りたい立場)
  • 提供者(実装者。できなければならない動きを用意する側)

この分離の概念はOOPだけに特有といったものではないが、OOPにとって重要である。(関連: 責任(responsibility)、メッセージ・パッシング)

この宣言と実装の分離は、利用者にとっての操作の可読性の向上とともに、オブジェクトという概念を成り立たせたいOOPにとっては オブジェクト間の結合を疎にする(あるいは結合を分かりやすくする)使い方にも利用される。


[編集] メッセージ・パッシング

(この節は書きかけです)

メッセージ・パッシングの図解
拡大
メッセージ・パッシングの図解

メッセージ・パッシング(message-passing)とは、オブジェクト間でメッセージを送受信することである。


基本的にオブジェクトは自身が持つデータを操作することができるが、他のオブジェクトの持つデータは直接操作しない。代わりにメッセージを送信し、相手オブジェクトがメッセージを受け取るという仕組みを介して間接的に操作する)。データをどう操作するかは、メッセージを受け取ったオブジェクトに任せる。


メッセージは、データの操作を相手に任せる操作であるという点が大きい。これにより、オブジェクトの関連によって問題を解決するといったプログラムを組むことが出来る。エイトクイーンパズル


次に、メッセージ・パッシングではない別の構造、引き出しモデルを引き合いに出して説明する。

引き出しモデルの図解
拡大
引き出しモデルの図解


引き出しモデルでは、データはストレージ上に並べられ、手続きはそのデータを操作する。ここでは、データ構造とコードの関連性がはっきりとは目に見えない。また、オブジェクトの振る舞いが関わりあって問題を解決するといったプログラムを目に見えるように組むことが難しい。


[編集] オブジェクトが持つカプセル化という性質

オブジェクトは基本的にブラックボックスである。即ちプログラマーは次の2つを意識してオブジェクトを作成する。

  • どのようなメッセージを受け取って処理できるかという仕様だけがオブジェクトの利用者に公開される。
  • メッセージをどのように処理しているかについての詳細は基本的にはオブジェクトの利用者に対して隠される。

ここで言う利用者とは狭義には利用元のオブジェクト、広義には利用元のオブジェクトを記述するプログラマを指す。この特徴をオブジェクト指向プログラミングでは特にカプセル化 (encapsulation) あるいは情報隠蔽 (information hinding) という。


[編集] メッセージ・パッシングの仕組み

(この節は書きかけです。ここから再構成前の内容が続きます)

ここで一例としてオブジェクトaが オブジェクトbにメッセージを送信する場合を説明する。

---+  メッセージ     +---+  メッセージ   +---+  メッセージ    +---
...|-------------> | a +------------> + b +------------> +...
---+               +---+              +---+              +---

ここで説明を簡略化するために次のように簡略化する。

  • a … 私 … (メッセージを)投げかけるオブジェクト (オブジェクトにはコンピューターを操作している人間も含む)
  • b … 友人 … (メッセージに)応えるオブジェクト


  • 私には実現したい仕事がある。私は何を期待しているかについて十分に説明でき、期待の実現に必要となるであろう十分な情報も揃えている。しかし、どうやって仕事を実現すればいいのか分からない。
  • そこで私が最初に自分の責任で決めなければならないのは、説明と情報を渡すことで 私の考えている仕事を達成してくれだろう十分に信頼のおける友人を選ぶことである。
  • 数ある友人らは 自分がどのような仕事を行えるかといった責任をある程度説明している。そこから考えて私は、ここでは友人bを選択したこととする。
  • 私は友人に、十分な説明と情報を含めたメッセージを投げかける
  • 一般的にオブジェクトにメッセージを送信すると説明されるが、概念上はオブジェクトに聞く、及びオブジェクトに一文(国語で言うところの単文)で指示するに近い。
  • ここで友人は、そのメッセージに対してどう振舞おうと自由である。ただ、私のメッセージに対して正しく答える責任はあるので それにはその通り応える。また、友人はメッセージに対して適切に応えることができないこともある。そのような場合は 私による友人選択判断ミスである。
  • オブジェクトは、受け取ったメッセージを叶える(振る舞う)。
  • 叶える責任はメッセージを受け取った側にある。その責任を果たすことだけが必要で、そのメッセージを叶えた方法(メソッド)は、見せない(メッセージを送った側からすれば、見ない)。
  • 友人はメッセージに対してどのようなメソッドを採るか選択することができる。例えば友人は、そのまた友人(友人の友人)にメッセージを投げかけたりもできる。その方法に対して私は知ることはしない。ただメッセージ通りの振る舞いをすればよい。
  • 私は、メッセージ通りに振る舞った友人の働きにより、仕事を実現する。


この構造を全体的に俯瞰すると、次のような構造になっている。
aもまたメッセージを投げかけられたオブジェクトかも知れないし、bもまた他のオブジェクトにメッセージを投げかける側のオブジェクトかもしれない。よくよく見れば、(全てとは言わないまでも)多くのオブジェクトの立場は メッセージに応える側であり、かつメッセージを投げかける側である。このようにオブジェクトとオブジェクトの関連性は抽象的に考えると再帰的な構造をしている。


オブジェクト指向以前のプログラミング(構造化手法で組まれたプログラムのうち、オブジェクト指向をしていないプログラミングを指す)では、次のような点を考えることに重点が置かれた。
データ構造を利用する側は、データ構造を知り、どうプログラムを組めば欲しいデータを得られるかについて考えた。
オブジェクト指向プログラムでも構造に変わりは無いが、利用の仕方の重点が次のように移った。
データ構造を利用する側は、そのデータ構造にはどのような振る舞いが用意されているかを把握してメッセージを投げかけ、欲しい構造で用意された結果だけを受け取る。
この違いは次のように言える。
データ構造は自らの振る舞いに対して責任(responsibility)を持った。データ構造を使おうとしている側にプログラムを組ませるのではなく、データ構造自らがそのデータにアクセスするプログラムを持った。このデータ構造で何ができるかは、データ構造自らが外部に向けて説明を公開する。データ構造を使う側は、そのデータ構造の内部に詳しくアクセスする必要がなくなった。オブジェクトとオブジェクトの関係は、内部構造ではなく、振る舞いの責任と、投げかけるメッセージという関係で結合する。これは結合関係を弱める方向に働くという好ましい効果がある。

[編集] メッセージとは

メッセージとは形式の定まった情報である。しばしばプログラム内で処理する必要のある特定のイベントや要求の通知を表している。

[編集] プログラムの全体的な構成

オブジェクト指向プログラミングでは オブジェクトを単位とし、処理の連鎖の全体として次のようにプログラムを記述・構成する。

  • 1. オブジェクトはメッセージを受け取ると、自身が保持する情報と受け取ったメッセージの内容を元に計算処理を行う。…(a)
  • 2. 前述aの結果に応じて自身が保持している情報を書き換える。…(b)
  • 3. 前述bの際、必要があれば更に他のオブジェクトに対し適当なメッセージを送信する。

[編集] オブジェクトの構成と、その記述について

オブジェクトは 大枠としては 次のように記述される。

  • プログラムを構成するのと同じ方法を再帰的に用いる。

つまりオブジェクトはその記述内で、メッセージを送って他のオブジェクトを利用している。ここでいう その「他のオブジェクト」もオブジェクトである(ここで再帰している)。

[編集] 抽象的にプログラミングできる可能性がある

(この記述は書きかけです。抽象データ型、is-a、ポリモーフィズム、継承、オーバーライド、クラス、インスタンスについて記述してください。総称型インターフェースとの違いに注意)

既存の複数のサブシステムと連絡を取るアプリケーションを開発することになったとする。サブシステムとは何かについては秘密で、開発部門に知らされることはないものとする。サブシステムaからサブシステムbに情報が流れるのだが、どのような形式で情報が流れるかはまだ設計が確定していないので分からない。

ここでもし形式が確定するまで待っていると、その待っている間の開発期間を損失する。ここでとりあえず、 SubSystem というそのまんまの名前のオブジェクトを想定し開発を進めるものとする。

SubSystem ----> SubSystem
 a               b

そしてとりあえず、SubSystemは次のようなメッセージを投げかけることは決まっている。

届け先SubSystem○×△はこちらから送り出す情報○×△を受け取って欲しい
SubSystem.send( Information information, SubSystem destination)

ここで、SubSystemとInformationは抽象的である。具体的なオブジェクトは、後にSubSystemとInformationの詳細が決まった際に定義すれば良い。データ構造の詳細が決まるまでの間に、「サブシステムaからサブシステムbに情報が流れる」というはっきりと確定した抽象的なコードは、十分に書いておくことが出来る


[編集] 仕組み

この節は執筆の途中です この節は、書きかけです。加筆、訂正して下さる協力者を求めています。

[編集] データと手続きから、オブジェクトとメッセージへ

オブジェクト指向プログラミングの説明に入る前の導入として4段階に分けて次に説明する。

  1. 従来の手続きについて
    プログラムを記述する上で、従来は与えられたデータをどのように処理しているかという手続き内容が意識された。手続きの中にはひとまとまりの理屈ではなく、単に手順がつらつらと続いているだけものもあり、そのコードの働きは何なのかプログラム全体を読むまで判断できないといった、規模によっては大きな負担がプログラマにかかることもあった。この事から、常に手続きは手短で影響範囲の限られているひとまとまりの理屈で区切られていることが好ましい。
  2. 従来のデータについて
    アプリケーション中には基本的にデータがいくつも存在する。もし、どこで何に使われているか分かりづらいデータがアプリケーション中に多く散見され、しかもそのデータが利用されているようであれば、そのアプリケーションの安定的な動作についてプログラマは迂闊に手出しができなくなる。どこで何に使われているか分からないデータには出会わないほうが好ましい。
  3. そこで、アプリケーションの開発をより安定したものとして続けるためには プログラマから負担を減らすために次の2点を実現する必要がある。
    • 手続きのひとまとまり当たりの記述量を減らす。
    • どこで何に使われているか分かりづらいデータを減らす。
  4. 上記の手続きとデータの問題を同時に解決する方法として
    特定のデータに対してのみアクセスしているようなデータとの関連性の強い手続きと、特定のまとまりに対して使われているだけのまとまりとしての関連性の強いデータをひとくくりにしておき、データと手続きの両者を離さない、という作り方がある。これで手続きとデータの影響範囲を同時に制限する。

このデータと手続きが不可分になっているという性質を利用して、概念上、オブジェクトというまとまりを作る。

仮にここで、「ウィンドウ」というオブジェクトがあるとする。ウィンドウには幅やタイトルなどのデータと、サイズ変更や表示位置の移動といった振る舞いを持つ。このオブジェクトに対してプログラマは、ウィンドウに対してデータや手続きの詳細を理解しようとしなくても「閉じる」といったメッセージを伝えることでウィンドウが閉じられるのであれば理解しやすい。こうなると、「データ」と「手続き」を理解することに煩わされがちだったプログラミングは、「オブジェクト」と「メッセージ」という、表面的な理屈だけでもある程度捉えることができる記述に近づく。

[編集] オブジェクトを作る仕組み・記述の違いによる分類

また多くのオブジェクト指向言語は 次のような分け方もできる。

クラスベース (class-based)
オブジェクトそのものではなく、その集まりであるクラスを通じてオブジェクトを定義する。そしてクラスベースの言語の多くはクラスの間に包含関係を認めることで類似するクラス間を関連付けたり、クラス間で重複する記述を省略したりする継承 (inheritance) という仕組みを備えている。
インスタンスベース (instance-based)

[編集] 背景

オブジェクト指向プログラミングという考え方が生まれた背景には計算機の性能向上によって従来より大規模なソフトウェアが書かれるようになってきたということが挙げられる。大規模なソフトウェアが書かれコードも複雑化してゆくにつれ、ソフトウェア開発コストが上昇し、1960年代には「ソフトウェア危機 (software crisis)」といったようなことも危惧されるようになってきた。そこでソフトウェアの再利用、部品化といったようなことを意識した仕組みの開発や、ソフトウェア開発工程の体系化(ソフトウェア工学 (software engineering) の誕生)などが行われるようになった。

このような流れの中で、プログラムを構成するコードとデータのうちコードについては手続き、や関数といった仕組みを基礎に整理され、その構成単位をブラックボックス とすることで再利用性を向上し、部品化を推進する仕組みが提唱され構造化プログラミング (structured programming) として1967年にエドガー・ダイクストラ (Edsger Wybe Dijkstra) らによってまとめあげられた(プログラミング言語の例としてはPascal 1971年)。しかしデータについては相変わらず主記憶上の記憶場所に置かれている限られた種類の基本データ型の値という比較的低レベルの抽象化から抜け出せなかった。これはコードはそれ自身で意味的なまとまりを持つがデータはそれを処理するコードと組み合わせないと十分に意味が表現できないという性質があるためであった。

そこでデータを構造化し、ブラックボックス化するために考え出されたのが、データ形式の定義とそれを処理する手続きや関数をまとめて一個の構成単位とするという考え方でモジュール (module) と呼ばれる概念である(プログラミング言語の例としてはModula-2 1979年)。しかし定義とプログラム内の実体が一対一に対応する手続きや関数とは異なり、データはその形式の定義に対して値となる実体(インスタンスと呼ばれる)が複数存在し、各々様々な寿命を持つのが通例であるため、そのような複数の実体をうまく管理する枠組みも必要であることがわかってきた。そこで単なるモジュールではなく、それらのインスタンスを整理して管理する仕組み(例えばクラスとその継承など)まで考慮して生まれたのがオブジェクトという概念である(プログラミング言語の例としてはSimula 1962年)

Simulaのオブジェクトとクラスというアイデアは異なる二つの概念に継承される。一つはシステム全てをオブジェクトの集合と捉え、オブジェクトの相互作用をメッセージに喩えた「オブジェクト指向」である。オブジェクト間の相互作用をメッセージの送受と捉えることで、オブジェクトは受信したメッセージに見合った手続き単位(≒関数)を自身で起動すると考える。結果オブジェクトは自身の持つ手続きのカプセル化を行うことができ、メッセージが同じでもレシーバオブジェクトによって行われる手続きは異なる――多相性を実現した(このメッセージを受け実行される関数は、メッセージで依頼されたことを行うための「手法」の意味でメソッドと呼ばれる)。この思想に基づき作られたのがSmalltalk(1972年)であり、オブジェクト指向という言葉はこのとき作られた。

一方、Smalltalkとは別にSimulaの影響を受け作られたC++(1979年)は抽象データ型のスーパーセットとしてのクラス、オブジェクトに注目し、オブジェクト指向をカプセル化、継承、多相性をサポートするものと再定義した。これらは当初抽象データ型派生、仮想関数と呼ばれ、オブジェクトのメンバ関数を実体ではなくポインタとすることで、継承関係にあるクラスのメンバ関数のオーバーライト(上書き)を可能にしたことで、多相性を実現した(この流儀ではメッセージメタファはオブジェクト指向に必須ではないものと定義し、オブジェクトの持つ手続きをメソッドとは呼ばずメンバ関数と呼ぶ)。

Smalltalkはこの「全てをオブジェクトとその相互作用で表現する」というデザインに立ち設計されたため、全てをファイルと捉えるファイル指向OS、プログラムをフロー制御された手続きと捉える手続き型言語からの脱却が行われた。そのためSmalltalkは自身がオブジェクト指向OSでもあること、メッセージ式のみで構成される文法などの特徴を持った。これは当時のプログラム言語としては特異的であり、ガベージコレクタを必要としインタプリタ形式で実行される処理の重さも手伝って先進的であるが普及しがたいものであると捉えられた。また、メッセージでの多相性は変数へのオブジェクトの動的束縛が前提となるため、静的型チェックが難しい。

C++の再定義した「オブジェクト指向」はこれらの問題を全てクリアにできることと、既存言語の拡張としてオブジェクト指向機能を実装できることでブレイクスルーを迎え急速に普及する。これによりメッセージ送信という考え方はやや軽視されるようになり、オブジェクト指向とはC++の再定義したものと広く認知されるようになった。

1980年代後半に次々と生まれたオブジェクト指向分析・設計論は、Smalltalkを源流とするオブジェクト指向を基に組み立てられた。このときSmalltalkは健在であったが広く普及しているとは言えずC++で実装する機会が多かったが、思想的にやや異なることと、マルチパラダイム言語として設計されたことに起因する文法の複雑さが問題とされた。このニーズを受けC++の提示した現実解と、Smalltalk的理想論を融合するものとして、文法面ではシンプル化しながらも強くC++の影響を受けつつ、一方で用語や思想面でSmalltalk色を濃くしたJava(1991年)が作られた。バランス感覚に長けたJavaの登場によってオブジェクト指向開発に必要な要素が全てそろい、1990年代後半からオブジェクト指向は爆発的普及を遂げる。

2005年現在、今後のオブジェクト指向プログラミングの流れとしてオブジェクト指向を補完するエージェント指向アスペクト指向といった方法論や、RubyPythonGroovyといった動的言語 (Dynamic Language) の 認知度が上がり、普及への萌芽が見られる。

[編集] オブジェクト指向言語一覧

オブジェクト指向プログラミングをサポートする機能を備える代表的なプログラミング言語としては以下のようなものが挙げられる:

Simula 1962年
オブジェクトとクラスを導入した最初の言語。またC++が再定義したオブジェクト指向言語の要件を満たすことから、最初のオブジェクト指向言語とされることもある。クラスベース。当初はシミュレーション記述用で後に汎用化。
Smalltalk 1972年
オブジェクト間の相互作用にメッセージというメタファを導入した最初の言語。オブジェクト指向と言う言葉はSmalltalkのプログラミングスタイルを説明するために作られた。動的な型付けにより高い柔軟性を持つ。
C++ 1979年
C言語のオブジェクト指向拡張、Simula言語風にクラスを定義でき、C言語の型システムを強化している。当初はC言語に対して上位互換であった他、強い型付けによりC言語譲りの実行効率の高いコードが生成できる。
Objective-C 1983年
C言語のオブジェクト指向拡張。C言語のコードとSmalltalk型のオブジェクトシステムを混在させたもの。オブジェクトシステム自体はCで書かれたランタイム。
Eiffel 1986年
強い型付けを行う型システムや表明など堅牢性を強く意識して設計されたオブジェクト指向言語。C++にテンプレートが導入される前に総称型を導入していた。
Self 1987年
最初のインスタンスベースのオブジェクト指向言語。
CLOS 1988年
関数型言語Common Lispのオブジェクト指向仕様。
Modula-3 1988年
モジュールを実現していたModula-2言語のオブジェクト指向拡張。
Python 1990年
最初のオブジェクト指向スクリプト言語。
Sather 1990年
Eiffelを拡張したもの。実行効率面での工夫が見られる。
Java 1991年
仮想マシン上で動作することによる高い可搬性リフレクションスレッドの標準サポートと充実したライブラリ群に定評があり、C++言語と人気を二分するオブジェクト指向言語。
NewtonScript 1993年
PDA環境用に修正されたSelf言語。PDAの性質を生かすため永続オブジェクトをサポートしている。
Ruby 1993年
オブジェクト指向スクリプト言語。クラスのMix-inなどのユニークな機能を持つほか、正規表現に渡るまで全てがクラスとして実装されていることが特徴。
Adaのオブジェクト指向拡張 1995年
多分最も仕様が複雑なオブジェクト指向言語。
Object Pascal (Delphi) 1995年
Pascal言語のオブジェクト指向拡張。
JavaScript 1996年
ウェブページ上で実行することを主目的に開発されたスクリプト言語。
OCaml 1996年
関数型言語MLのオブジェクト指向拡張。クラス型推論機構に組み込まれているという特徴がある。
C# 2000年
Javaとよく似た作りでJavaと同じく仮想マシン上で動作するが細かく色々と拡張されている。.NET Framework上で動く。
COBOL 計画中
オブジェクト指向機能を取り入れた規格の拡張が計画されている。


これらは次の2つに分類できる。

ハイブリッド型オブジェクト指向言語 (hybrid object-oriented language)
非オブジェクト指向言語にオブジェクト指向機能を拡張したもの。Simula、C++およびObjective-C、CLOS、Object Pascalなど。(Objective-CやCLOSはオブジェクト指向部分そのものは純粋。C++などは既存文法の拡張に当たる)。
純粋なオブジェクト指向言語 (pure object-oriented language)
当初からオブジェクト指向言語として設計されたもの。Smalltalk、Eiffel、Self、Java、Rubyなど。

これらの言語では、クラスの定義、インスタンスの生成、オブジェクト間の通信を構文または専用の関数などでサポートしている。

オブジェクト指向言語では継承の利用とあいまってオブジェクトへの参照ポインタが多用される関係で、オブジェクトのメモリへの割り当てのため自動ガベージコレクション機能を備えているものが多い。しかしすべての言語が備えているわけではない。例えば、C++やObjective-Cはガベージコレクションを備えていない(Mac OS XではCocoaが担当しているのであり、Objective-C自体の機能ではない)。

[編集] オブジェクト指向言語の仕組み

相互にメッセージを送りあうオブジェクトの集まりとしてプログラムを構成することができる仕組みを持つ。 そのために、少なくとも オブジェクトについての3つの仕組みと、オブジェクトの管理についての3つの仕組みが必要となる。

オブジェクトの仕組み
* オブジェクトに蓄えられる情報、データを表現する仕組み。
* 他のオブジェクトにメッセージを配送する仕組み。
* 受け入れ可能な各種メッセージに対応して、処理する事柄を記述する仕組み(メソッド)。
オブジェクトを管理する仕組み
* オブジェクト間の関係を整理分類して系統立てる仕組み。
* 必要なオブジェクトを作成・準備する仕組み。
* 不要なオブジェクトを安全に破棄する仕組み。

これらをどのように言語の要素として提供し、どのような機械語コードで実現するかによって様々なオブジェクト指向プログラミング言語のバリエーションが生まれる。以下、オブジェクト指向言語が提供する様々な要素が上記の仕組みをどのように実現しているかについて概観する。

[編集] オブジェクトの概念と実際

オブジェクト (object) はオブジェクト指向プログラミングの中心となる概念であり、この概念を実際にどう実現するかはプログラム言語による。 以下、概念と実際がどう対応しているかについて説明する。

  • 概念的には 各々のオブジェクトは、プログラムが表現する情報システムの中で 能動的な役割を持った存在を表現している。
  • 概念的には メッセージを受け取り、その処理の過程で内部に蓄えたデータを書き換え、必要に応じて他のオブジェクトへメッセージを送るといった動作をしている。
  • 概念的には コードとデータが一つになっている。


[編集] オブジェクトという概念の実現のされ方

実際のプログラムでは、全てのオブジェクトが互いに全く異なった存在ではなくオブジェクトは種類に分けることが出来る。

例えば勤怠管理のシステムであれば、氏名や年齢、累積勤務時間などのデータは異なっても社員は皆、出勤し退勤するという処理(振る舞い)は同じだろう。このように複数の異なるオブジェクトが同じ種類のメッセージを受け取り共通の処理をするのが普通である。

このような場合、各オブジェクトがそれぞれメッセージ処理のコード(前述の振る舞いに当たる)を独自に備えていては無駄である。 そこでオブジェクト指向言語がオブジェクトを実現する際には多くの場合、内部的にはオブジェクトを2つの部分に分けている。

[編集] 同一種類のオブジェクトの間で変わらない共通部分

一つは同一種類のオブジェクトに共有される部分、例えばメッセージ処理のコード(振る舞い)や定数(どのオブジェクトでも異ならないデータ)の類である。

[編集] 同一種類のオブジェクトの間で変わる個々の部分

もう一つは同一種類のオブジェクトでもそれぞれ異なる部分、典型的には各オブジェクトが保持するデータ群である。

[編集] メッセージの処理のされ方

そしてあるオブジェクトOにメッセージを配送し適切なメッセージ処理コード(振る舞い)を呼び出す際には、まず対象となるオブジェクトOについて共通部分の格納場所を見つけて適切なコードを選び出し、次にそのコードに対して処理対象となるオブジェクトO固有のデータの所在を示すオブジェクトIDを渡すようになっている。

各オブジェクトの固有データを識別するオブジェクトIDを表現する方法も様々で、オブジェクトのIDとしては名前、番号なども用いられることがあるが、多くのオブジェクト指向言語ではオブジェクトの固有データを記憶している主記憶上のアドレスがそのまま用いられる。アドレスを直接利用することは非常に実行効率の向上に寄与するが、プログラム間でのオブジェクトの受け渡し、セッション間(プログラムが終了して再度起動された時など)でのオブジェクトの受け渡しにはそのまま利用することができない。

また各オブジェクトの固有データから共通部分の格納場所を見つける方法もまた各言語により異なり、その言語の開発目的に応じて実に多種多様である。

[編集] JavaScriptの場合

例えばJavaScriptの場合、各オブジェクトは連想配列であり、名前で表現されたメッセージのIDからメッセージ処理コードである関数への参照を直接見つけ出す。各オブジェクトの固有データもその連想配列に格納されていて、メッセージを処理する関数には連想配列のアドレスが渡される。

[編集] Selfの場合

Selfのようなインスタンスベースのオブジェクト指向言語ではプロトタイプとなるオブジェクトがメッセージを処理するコードも保持しており、オブジェクトがクローンされて作成されるときにそのプロトタイプのありかを示す情報もコピーされ、メッセージは受け取ったオブジェクトのIDを添えてプロトタイプに送られて処理される(Selfでは実行効率上の問題から後に内部的にクラスを作って利用するようになっている)。

[編集] クラスベースの言語の場合

最も普及しているクラスベースの言語では共通部分はオブジェクトの種類を表現するクラスに保持され、各オブジェクトは固有データと共にそのクラスのIDを保持する。そしてオブジェクトに送られるメッセージはその送り先オブジェクトにあるクラスのIDからクラスを見つけ、その中からメッセージを処理するコードを見つけ出し、処理対象となっているオブジェクトのIDを付してそのコードを呼び出す仕組みになっている。

[編集] メッセージ

メッセージ (message) はオブジェクト間の通信でやりとりされる情報である。メッセージはあて先となるオブジェクトのオブジェクトIDとメッセージ種別を示すIDとメッセージの種別に応じた追加の情報からなる定まった形式を持つ。追加の情報はそれ自身が何らかのオブジェクトやオブジェクトのIDである場合もある。メッセージの配送には大別して2つの方式がある:

同期式
オブジェクトがメッセージの送信を依頼すると相手が受信、処理して結果を返すまでそのオブジェクトは処理を中断して待つ。
非同期式
オブジェクトがメッセージの送信を依頼した後、相手の応答を待たずにオブジェクトは処理を続行する。処理結果は別のメッセージとして返される。

両者とも一長一短がありどちらがすぐれているとは言えない。また並列・並行処理が可能な環境では一方の仕組みがあれば、それを利用してもう一方も実現可能である。一般的な傾向としては、メッセージの伝送や処理に時間が掛かる場合は非同期式の方が効率は良く、そうでない場合には同期式の方が挙動が分かりやすく利用しやすい。

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

[編集] クラス

クラス (class) は大多数のオブジェクト指向言語で提供されている仕組みであり、上記の機能の殆ど全てに関わりがある。概念的にはクラスはオブジェクトの種類を表す。このためオブジェクトはクラスに「属する」という言い方をする。あるクラスに属するオブジェクトのことをそのクラスのインスタンス (instance) と呼ぶ。データ型の理論から見た場合クラスは型を定義する手段の一つである。クラスによってオブジェクトを記述する言語をクラスベース (class-based) のオブジェクト指向言語と呼ぶ。

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

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

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

[編集] インスタンスベース

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

  • Self
  • JavaScript
  • NewtonScript
  • ドリトル
  • Squeak eToys(Squeakの非開発者向けビジュアルスクリプト言語。SqueakToys とも)

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

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

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

[編集] データメンバ

データメンバ (data member) は他のオブジェクトに対する参照ポインタであるか、他のオブジェクトそのものである。参照かポインタである場合にはそのデータメンバの参照するのはデータメンバが記述されているクラスそのもののインスタンスに対する参照であっても良い。

一般にデータメンバはインスタンスデータメンバクラスデータメンバの2種類に大別できる。効率上の観点から言語が提供する基本オブジェクトの定数を表すデータメンバは特別扱いされる。そのような定数を表すデータメンバを特に定数データメンバ (constant data member) と呼ぶ。データメンバはメンバ変数 (member variable) と呼ばれることもある。

[編集] インスタンスデータメンバ

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

Smalltalkではインスタンス変数 (instance variable) と呼ばれる。

[編集] クラスデータメンバ

クラスデータメンバはそのクラスのインスタンスの間で共有されるデータである。

Smalltalkではクラスデータメンバはクラス変数 (class variable) と呼ばれる。また、C++Javaでは歴史的事情によりクラスデータメンバは静的データメンバ (static data member) と呼ばれる。

[編集] 定数データメンバ

クラスで定義される定数データメンバは値が変わらないので一般にクラスデータメンバであることが多い。

[編集] メソッド

メソッド (method) は特定の種類のメッセージの処理方法を記述したものである。メソッドもインスタンス・メソッドとクラス・メソッドの2種にできる。インスタンス・メソッドはそのクラスの各インスタンスが個別に処理し、クラス・メソッドは各インスタンスとは無関係に実行される。インスタンス・メソッドの集まりはそのクラスのインスタンスが処理可能なメッセージのカタログの機能を果たす。インスタンス・メソッドは単にメソッドと呼ばれることも多い。

[編集] 他言語と比較したC++のメソッド

C++ではメソッドはメンバ関数 (member function) や関数メンバ (function member)と呼ばれる。これはC++がクラスを抽象データ型の拡張と位置づけ、非メッセージメタファな言語思想を持っている為である。これら言語ではメソッドをオブジェクト(=クラスインスタンス)の持ち物として捉えず、クラスに定義されたフューチャーであると考える。メッセージメタファを否定するため、同時にメッセージを実行するメソッド(手法)ではありえない。

[編集] クラスメソッドについて

クラス・メソッドだが、オブジェクト指向の本義に立ち返れば、クラス・メソッドがあるということはクラスがメッセージをレシーブできるという事になる。これは即ちクラスがオブジェクトであることを意味する。

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

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

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

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

[編集] クラスメソッドの呼び方について

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

[編集] 特定の機能の割り当てについて

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

[編集] 初期化と廃棄時に利用されるメソッド

初期化に利用されるメソッドをコンストラクタあるいは構築子 (constructor)、廃棄時に利用されるメソッドをデストラクタあるいは消滅子 (destructor) と呼んで特別に扱うことが多い。

構築子が純粋に初期化だけを担う場合はイニシャライザあるいは初期化子 (initializer) と呼ばれることもある。

Javaでは消滅子をファイナライザ (finalizer) と呼ぶ。

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

C++・Javaの場合、各クラスの名前がコンストラクタの名前として使用される。C++では一部のコンストラクタは型変換演算子として、また暗黙の型変換にも利用される。

[編集] アクセス権

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

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

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

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


[編集] 関連項目

THIS WEB:

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - be - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - closed_zh_tw - co - cr - cs - csb - cu - cv - cy - da - de - diq - dv - dz - ee - el - eml - en - eo - es - et - eu - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gd - gl - glk - gn - got - gu - gv - ha - haw - he - hi - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mg - mh - mi - mk - ml - mn - mo - mr - ms - mt - mus - my - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - rm - rmy - rn - ro - roa_rup - roa_tara - ru - ru_sib - rw - sa - sc - scn - sco - sd - se - searchcom - sg - sh - si - simple - sk - sl - sm - sn - so - sq - sr - ss - st - su - sv - sw - ta - te - test - tet - tg - th - ti - tk - tl - tlh - tn - to - tokipona - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu

Static Wikipedia 2008 (no images)

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - bcl - be - be_x_old - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - co - cr - crh - cs - csb - cu - cv - cy - da - de - diq - dsb - dv - dz - ee - el - eml - en - eo - es - et - eu - ext - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gan - gd - gl - glk - gn - got - gu - gv - ha - hak - haw - he - hi - hif - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kaa - kab - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mdf - mg - mh - mi - mk - ml - mn - mo - mr - mt - mus - my - myv - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - quality - rm - rmy - rn - ro - roa_rup - roa_tara - ru - rw - sa - sah - sc - scn - sco - sd - se - sg - sh - si - simple - sk - sl - sm - sn - so - sr - srn - ss - st - stq - su - sv - sw - szl - ta - te - tet - tg - th - ti - tk - tl - tlh - tn - to - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu -

Static Wikipedia 2007:

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - be - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - closed_zh_tw - co - cr - cs - csb - cu - cv - cy - da - de - diq - dv - dz - ee - el - eml - en - eo - es - et - eu - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gd - gl - glk - gn - got - gu - gv - ha - haw - he - hi - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mg - mh - mi - mk - ml - mn - mo - mr - ms - mt - mus - my - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - rm - rmy - rn - ro - roa_rup - roa_tara - ru - ru_sib - rw - sa - sc - scn - sco - sd - se - searchcom - sg - sh - si - simple - sk - sl - sm - sn - so - sq - sr - ss - st - su - sv - sw - ta - te - test - tet - tg - th - ti - tk - tl - tlh - tn - to - tokipona - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu

Static Wikipedia 2006:

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - be - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - closed_zh_tw - co - cr - cs - csb - cu - cv - cy - da - de - diq - dv - dz - ee - el - eml - en - eo - es - et - eu - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gd - gl - glk - gn - got - gu - gv - ha - haw - he - hi - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mg - mh - mi - mk - ml - mn - mo - mr - ms - mt - mus - my - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - rm - rmy - rn - ro - roa_rup - roa_tara - ru - ru_sib - rw - sa - sc - scn - sco - sd - se - searchcom - sg - sh - si - simple - sk - sl - sm - sn - so - sq - sr - ss - st - su - sv - sw - ta - te - test - tet - tg - th - ti - tk - tl - tlh - tn - to - tokipona - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu