豆知識・お役立ち情報

クリエイター・プログラマーを目指している人のためのメディアくりぷろメディア-クリエイター・プログラマーを目指している人のためのメディア

2023.11.25更新

オブジェクト指向の難関-初心者でも「なるほど」とわかる抽象クラス

オブジェクト指向の難関-初心者でも「なるほど」とわかる抽象クラス

オブジェクト指向の勉強を進めていくうえで、結局最初につまづくところはこの「抽象クラス」「インターフェイス」「ポリモフィズム」の部分ではないかなぁ、と思うのです。
クラスの定義、インスタンス、クラスの継承、あたりまでは「簡単、簡単!」と思っていても、やはりこのあたりで「???」と戸惑う方が多いと思うのです。

まずは「抽象クラス」から、初心者の方でも「なるほどー」と思っていただけるように、お話したいと思います。

この記事の流れ

  1. どのようなときに抽象クラスを使うのか?
  2. 抽象クラスとは「まだ定義されていないメソッド」が含まれている
  3. 抽象クラスにするメリット

どのようなときに抽象クラスを使うのか?

例えば、フルートやホルンなどを表す「楽器クラス」を作ることを考えます。
楽器クラスは「音を鳴らす」というメソッドを持っています。
この楽器クラスを継承して、フルートやホルンなどの個々の楽器クラスを作ると仮定しましょう。

この楽器クラスを定義する際に「音を鳴らす」メソッドを定義しようとして・・・何の音を鳴らせばいいのでしょう?
ホルン?フルート?

そうです。
楽器クラスの「音を鳴らす」メソッドは、まだ定義できないのです。何の音を鳴らすかは確定できないからです。
フルートなのか、ホルンなのか、何の楽器なのかが決まることで定義できるようになります。

ただし、楽器クラスを継承すると「音を鳴らす」メソッドは必ず実装されている、というルールは確定されている。

このような場合に「抽象クラス」を利用することができます。

抽象クラスとは「まだ定義されていないメソッド」が含まれている

抽象クラスとは「まだ定義されていないメソッドが含まれているクラス」です。
今回の例でいうと「音を鳴らす」メソッドが、その未確定のメソッドに当たります。
まだ未確定のメソッドがあるのです。
でもそのメソッドは必要なメソッドで、必ず定義してほしいメソッドです。

抽象クラスで「これは後で実装してね」とメソッドの名前や引数などの必要な情報だけ記述しておいて、
メソッドの動作が確定した時に、メソッドの定義が行われます。

今回の例では「フルートクラスを作るとき」「ホルンクラスをつくるとき」にどんな音を鳴らすのか確定されるので、
このクラスが作られるときにメソッドの定義がされることになります。

抽象クラスにするメリット

抽象クラスを利用するメリットは、大きく3つ考えられます。

  • まだ動作内容は決まっていないけれど、必要なメソッドを列挙できる。
  • 抽象クラスのままだとインスタンス化できないので、必要なメソッドを必ず実装してから利用してもらえる。
  • 抽象クラスを使うと「動作は定義し忘れではなく、定義してほしいです」と示すことができる。

まだ動作内容は決まってないけれど、必要なメソッドを列挙できる
楽器クラスを継承して作成されるクラスは、必ず「音を鳴らす」というメソッドが必要だと列挙することができます。

抽象クラスのままだとインスタンス化できないので、必要なメソッドを必ず実装してから利用してもらえる
抽象クラスを継承して、さらに抽象クラスを作ることは可能です。
ですが、最終的にインスタンス化して利用したい場合は、抽象クラスのままではできません。
必ずすべてのメソッドの動作を定義して、未確定のメソッドがない状態にしなければなりません。
つまり、インスタンス化して利用するためには「未確定メソッドはなくして、通常のクラスとして完成させる」必要があります。

これは一つのシステムを複数の人で開発する際にも、とても重宝します。
抽象クラスを使って「楽器クラスを継承する場合は、音を鳴らすメソッドの定義が必要なんだ」と、メンバー間で情報を共有できるようなものです。
未確定メソッドを定義させることを強制することができるのです。

もし抽象クラスを使わなかった場合は、Aさんは「音を鳴らす」というメソッド、Bさんは「奏でる」というメソッドで実装してしまうかもしれません。
また、「楽器は音を鳴らす」というルールのもとに開発しているのに、実装し忘れる人が出てくるかもしれません。

抽象クラスを使えば、そのようなことは起こりません。
仕様書に「楽器クラスを継承したら、音を鳴らすメソッドが必要です」と書かなくても、抽象クラスの定義をしておけばそれが仕様書のような役割を果たしているのです。

抽象クラスを使うと「動作は定義し忘れではなく、定義してほしいです」と示すことができる
例えば、Aさんが楽器クラスを定義する際に「音を鳴らす」メソッドを空っぽにして定義したとします。
もちろん、Aさんは「音を鳴らすメソッドは後で定義してもらおう」と考えています。

でも、楽器クラスを継承してフルートクラスを作成しようとしたBさんの立場になると
「これは動作を定義する必要があるのか」
「そもそも何も動かさないメソッドなのか、故意に動作を記述していないのか」
の判断ができません。

でも、楽器クラスを継承してフルートクラスを作成しようとしたBさんの立場になると
「これは動作を定義する必要があるのか」
「そもそも何も動かさないメソッドなのか、故意に動作を記述していないのか」
の判断ができません。

継承クラスを使っていれば
「あ、音を鳴らすメソッドの動作はこちらで定義する必要があるんだな」とわかります。
しなければ、インスタンス化ができないので利用できないからです。

まとめ

できるだけプログラミング言語などの知識がない方でもわかるように、簡単に簡単に解説してみました。
「クラスを利用する人のための、便利なクラスを作る人」の立場になって考えてみると、より理解が深まると思います。

少しでも皆さんの理解の助けになれれば、うれしいです。