クラス (コンピュータ)

From Wikipedia, the free encyclopedia

クラス: class)は、オブジェクト指向プログラミングにおいて、オブジェクトの構造と振る舞いを定義する仕組みであり、この定義から生成される実体をインスタンスと呼ぶ。

クラスには、オブジェクトが保持するデータと、それに対する操作がまとめて記述される。クラスは、クラスベースのオブジェクト指向プログラミングを構成する基本要素の一つである。

カプセル化 (encapsulation)

一般にどんなプログラムであれ、プログラム機能を提供するためにはデータを保有するだけではなく、データに対する操作ができなければならない。単に複数のデータをまとめる手段としては、C言語構造体Pascalのレコード型といった形で従来の手続き型プログラミング言語においても提供されている。一方クラスは、データだけでなくそのデータに関連する操作もひとまとめにして管理する枠組みを提供する。

このように関連する変数や操作などをクラスの所属物として一つにまとめてしまうことを、クラスによる情報のカプセル化(encapsulation)と呼ぶ。適切なカプセル化により、データ構造やアルゴリズムなどを変更したとしても、変更箇所はカプセル化されたクラス領域内だけで済み、変更箇所がクラス外の関連ソースコード全体にまで散乱・波及してしまうことを防ぐことができる。

またアクセス修飾子 (access modifier) により、所属物に対して公開/非公開情報の区別をつけることで、クラス外部からクラス内に対して破壊的操作を加えることを防いだり、特定の機密データをクラス外部から見ることができないようにしたりするなど、外部に開放する情報に制限をつけることができる。カプセル化した上に公開/非公開情報の区別を加えることを情報隠蔽(information hiding)と呼ぶ[1][注釈 1]

継承 (inheritance/extension/generalization)

継承(inheritance)または拡張(extension)とも呼ばれる。既存のクラスに基づき新たなクラスを構成する。その目的は、単純なクラスに基づいてもっと複雑なクラスを構成することである。また、複雑なクラスはそれを定義する単純なクラスに従属するという意味で、クラスに階層をつけることができるようになる[2][注釈 2]。継承の基になったクラスを親クラス基本クラス基底クラススーパークラスなどといい、継承してできたクラスを子クラス派生クラスサブクラスなどという。派生クラスのインスタンスはまた基本クラスのインスタンスとしても扱えるようになる(リスコフの置換原則)。継承により、後述のポリモーフィズムを実現することができるようになる。

UMLでは継承のことを汎化 (generalization) と呼んでいる。汎化とはスーパークラスによる抽象化であり、対義語の特化 (specialization) はサブクラスによる具象化を指す。

また、オブジェクト指向を効率よく使いこなすためには継承だけでなく集約 (aggregation)、委譲 (delegation) を理解する必要がある。

継承は、開放/閉鎖原則に基づき、単純な基本クラスからより複雑な派生クラスを構成する機構であり、コードの再利用と拡張を容易にする。逆に複雑なクラスの所属物のいくつかを除いて単純なクラスを構成しようとすると、コードの再利用と拡張を阻害することになる。

すなわち、最初から多数の所属物をカプセル化したり、基本クラスから継承するにしても多数の所属物を付け加えて極めて特化されたクラスを最初から作成してしまうと、途中でそれよりやや一般的なクラスが必要になっても代替させることができない。

複数の基本クラスを継承して一つの新しいクラスを派生させることを多重継承 (multiple inheritance) と呼ぶ。多重継承により、基となった全てのクラスの所属物は合わせて一つになり、全ての動作が組み合わさった新しい一つのクラスが構成される。ただし、実装の多重継承は二つの基本クラスの同名メソッドのオーバーライドによるコンフリクトを始めとするいくつかの問題点(菱形継承問題など)が指摘されている。したがって実装の継承は通例、一つのクラスに基づいてその拡張を行う単一継承を用いる。C++は多重継承を許可し、多重継承にまつわる問題の解決手段を仮想継承によって提供しているが、他の多くの言語、例えばJavaC#D言語では実装の多重継承はサポートされておらず、インターフェイスの複数実装による型の多重継承のみサポートされている。ただしJava 8以降はインターフェイスのデフォルト実装により、実装の多重継承も限定的にサポートするようになった。なお、Simula 67は多重継承もインターフェイスもサポートしていなかった[3]

C++ などの言語では、既存のクラスを継承したクラスを作ることで新たなメソッドの作成(追加)が可能となる。

ポリモーフィズム (polymorphism)

クラスを継承する際に、スーパークラスの振る舞いをサブクラスの振る舞いで上書きする(置き換える)ことをオーバーライドという。あるサブクラスのインスタンスがオーバーライドされた振る舞いを持つ場合、インスタンスの具体的な内容(クラス)が分からなくても、インスタンスに対してその振る舞いを実行するよう指示すれば、見かけがスーパークラスと同じ(すなわちインターフェイスが同じ)でありながら、インスタンスの実際のクラスに応じて実行される振る舞い(処理内容)を変えることができる。このようにして、見かけが一緒なのに動作が変わることをポリモーフィズム(ポリモルフィズム)多様性多態性多相性などという。

Simulaにおけるクラス

ダイクストラの構造化プログラミングは、プログラムの大規模開発への道を開いたが、あくまで単一スレッド(single thread)計算機を前提としたトップダウン型開発方法であった。すなわち、プログラムのすべての機能は単線の計算プロセス上で実行する必要があり、たとえ甲と乙という汎用的な単機能を提供する検証済みのプログラムがそれぞれ独立に存在していても、両機能を実現するプログラムを作成するためには、ソースコードから該当機能部分を抜き出し、単線上に乗るように連接(concatenation)した上で、一つのプログラムとして正しく動作するように修正し、さらに再度検証しなければならない。

一方で、複数スレッド(multi thread)計算機においては、主プログラムから、甲と乙のプログラムなどの従プログラムをそれぞれ並列に実行させた上で、処理内容を従プログラムに(OSの機能などを仲介して)伝言受け渡し(message passing)して代わりに処理させることで、検証済みプログラムのソースコードに手を加えることなく、低コストで開発することができる(コルーチンを用いたプログラミング)[注釈 3]

オーレ=ヨハン・ダールアントニー・ホーアは、このような考え方の有効性を主張し[4]、上記のような一連の操作を一つの言語の中で完結させるための機構を提案した。それがクラスの構文である。

ダールとホーアは、まず主プログラムから従プログラムを並列呼び出しする際、読み込みするにあたって新たに(new)割り当てられたメモリ領域に限定して走る計算プロセスを実例(instance;インスタンス)と名付け、さらにその実例の集まり(class of instances)をそれが記述されたソースコードと同一視した。その上で、呼び出されたときだけではなく、存在し続ける従プログラムの実例のもとになる手続きをクラス(class)、その実例を(「クラスの実例」ではなく)改めてクラスの対象(object)と名付けた[5]。さらに、その考えに基づいてSimula 67にクラスの構文を実装した[注釈 4]

脚注

参考文献

関連項目

Related Articles

Wikiwand AI