プログラミングの継承についてわかりやすく解説してみた
- 作成日: 2021-02-02
- 更新日: 2023-12-24
- カテゴリ: プログラミング
プログラミングにおける継承とは?
現代的なプログラミング言語を学んでいると、かならずこのワードが教材の中に出てきます。
それは「継承」です。
継承とは、オブジェクト指向における考え方の1つで、目的はクラスを拡張することです。
この記事ではプログラミングにおける継承の考え方を解説します。
具体的には↓を見ていきます。
- 継承ってなに?
- オブジェクト指向ってなに?
- 継承を使うとなにが便利なの?
- 継承は使わないといけないもの?
- Pythonによる継承の例
継承ってなに?
継承とはなんでしょうか?
継承とは、「他のクラスの機能を引き継いで新しくクラスを作る」ことを言います。
たとえばAnimal
というクラスがあったとします。
このクラスにはメンバ変数にname
という動物の名前を表す変数を持っています。
それからgetName()
という名前を取得するメソッド(関数)を持っています。
Animal
name ... 使える
getName() ... 使える
このAnimal
というクラスをベースにして、新しいCat
というクラスを作ることを特に「Animal
クラスを継承してCat
クラスを作る」と表現します。
Animal
クラスを継承するということは、Animal
クラスの持っている変数やメソッドをCat
クラスに引き継ぐということです。
つまりAnimal
クラスではname
というメンバ変数にアクセスできますが、Animal
クラスを継承したCat
クラスでも同様にname
というメンバ変数にアクセスできるようになります。
Cat 継承する→ Animal
name ... 使える
getName() ... 使える
このように他のクラスの持っているメンバ変数やメソッドを引き継いで新しいクラスを作ることを継承と言います。
オブジェクト指向ってなに?
継承とはオブジェクト指向の考え方です。
オブジェクト指向と言う大きな考えのまとまりがあり、その中に継承と言う考えが存在します。
オブジェクト指向は、プログラムにおいて名前が付くものを1つのオブジェクトとして扱ってプログラミング的に表現することを指します。
たとえば車のプログラムを作っていて、車と言うモノを表現するときにCar
というクラスを作ってオブジェクトにします。
そしてそのオブジェクトには変数やメソッドを持たせて、そのオブジェクトがオブジェクトらしく振る舞えるようにします。
たとえば車だったらCar
というクラスを作り、run()
というメソッドを持たせるでしょう。
これでrun()
を実行したら車が走るという表現をオブジェクト指向的に行うことが出来るようになります。
オブジェクト指向で大事な考え方は↓の3つです。
- カプセル化
- 継承
- ポリモーフィズム
カプセル化というのはクラスの中の変数などがクラスの外から見えないように隠蔽することを指します。
こうすることでクラスの隠蔽率が上がり、保守性の高いオブジェクトになります。
そして継承とは、先ほども解説しましたが他のクラスの機能を引き継いで新しくクラスを作ることを言います。
このときに継承するクラスの機能とは、クラスが持つ変数やメソッドのことです。
継承はこれらの機能を引き継いで、新しく作成したクラスに持たせることが出来ます。
そしてポリモーフィズムとは同じメソッドを使ってオブジェクトの振る舞いを変えることを指します。
たとえば足の速いSpeedCar
と足の遅いSlowCar
があるとします。
これらのクラスは2つともrun()
メソッドを持っていますが、同じrun()
メソッドを使っても両者の走るスピードは違います。
オブジェクト指向は1980年代から流行したプログラミングの考え方のメインストリームで、今でも根強い人気があります。
このオブジェクト指向にのっとったプログラミング言語も開発されています。
代表的なのはRuby
です。
🦝 < 他にもいろいろなプログラミング言語が影響を受けてるよ
🐭 < 今どきのメジャーな言語はほとんど影響を受けてるのかな?
継承を使うとなにが便利なの?
継承を使うと何が嬉しいのでしょうか?
1つは、コードの書く量を減らすことが出来ます。
Animal
というクラスを作っておいて、そのクラスに基本的な機能を備え付けておきます。
たとえば名前だったり、走らせるメソッドだったり、いろいろいつけておきます。
そしてAnimal
と似た性質を持つCat
というクラスを作る時に、このAnimal
というクラスを継承します。
そうすればCat
クラスは継承するだけでAnimal
の持つ名前や走らせるメソッドを使えるようになります。
Cat
でも名前や走らせるメソッドを新しく作る必要はなく、Animal
から機能を流用できるわけです。
Cat
クラスだけでなくDog
クラスを作りたくなった場合でも同様です。
Dog
クラスはAnimal
クラスを継承すれば、ほとんどの機能をそのまま使うことが出来ます。
変えるところは鳴き声ぐらいなので、それはDog
クラス内で鳴き声を変更します。
もう1つは、ポリモーフィズムを使えるということです。
たとえばCat
クラスからオブジェクトを作成してrun()
メソッドを実行させておくとします。
その処理はいわゆる動物が走っていればOKな処理です。
しかしCat
は足が早かったため、足の遅いSlowCat
クラスを新しく作って、すでにあるCat
クラスとすげ換えました。
この時、run()
メソッドを実行している所の処理は変更しなくてもいいことになります。
なぜならrun()
メソッドはSlowCat
クラスも持っているからです。
ポリモーフィズムを持たせることでプログラムの柔軟性が上がり、機能の変更などがしやすくなります。
コードをほとんど変えずに中身の機能をすげ換えることが出来るので、プログラムを書く側からすると非常に助かるわけです。
継承は使わないといけないもの?
ところで、プログラミングをやるからには継承は必ず使わないといけないのでしょうか?
実はそんなことはありません。
継承はたしかに便利な機能ですが、無理に継承を使う必要はありません。
なぜなら継承はプログラムを複雑にするからです。
最近の後発のプログラミング言語では、そもそも継承をサポートしていない言語もあるくらいです。
代表的なのはGo言語です。
Go言語は継承を不要と考えて、言語機能から継承自体を無くしてしまいました。
その代わりにインターフェースやメンバ変数のぶちまけなどが出来るようになっています。
継承を覚えると、安易になんでもかんでも継承で片づけようとします。これはあるあるです。
しかし、大抵の場合うまくいきません。私の経験則では、継承は安易に使うと高い確率で失敗します。
それほど継承はプログラムを複雑にするからです。
継承は便利ですが、かならずしも新しいプログラムで使わないいけないものではありません。
Go言語のようにインターフェースや変数のぶちまけに限定して使ったり、Rubyのようにミックスインとして利用するということが良い選択のように思えます。
最近のプログラミング界隈を見ていると、継承の評価は決して高いものではないのがちらほらと伝わってきます。
継承を使いこなすのは高い技能が必要です。そして継承は問題を複雑にします。
クラスによる問題を簡単にしたい場合はコンポジションやミックスインを多用するようにしましょう。
デザインパターンの分野ではかなり早い段階から継承よりコンポジションを使ったほうが柔軟性のある設計が可能なことが知られています。
Pythonによる継承の例
Pythonによるコードで実際の継承を見てみたいと思います。
今回作るのはAnimal
クラスとCat
, Dog
クラスです。
class Animal:
def __init__(self):
self.name = 'Animal'
self.voice = 'Ohohoh'
def say(self):
print(self.name, self.voice)
class Cat(Animal):
def __init__(self):
super().__init__()
self.name = 'Tama'
self.voice = 'Nyan'
class Dog(Animal):
def __init__(self):
super().__init__()
self.name = 'Pochi'
self.voice = 'Wan'
cat = Cat()
dog = Dog()
cat.say()
dog.say()
↑のコードを実行すると↓のような結果になります。
Tama Nyan
Pochi Wan
Cat
クラスもDog
クラスもAnimal
クラスを継承しています。
そしてメンバ変数(属性)であるname
とvoice
の値をちょちょいといじってます。
say()
メソッドはそのままAnimal
クラスのものを使っています。
このように継承を使うと簡単にクラスの機能を引き継ぐことが出来ます。
🦝 < 便利ですね
おわりに
今回はプログラミングにおける継承について見て見ました。
継承は便利ですが、その扱いはなかなか悩ましいものです。
みなさんもぜひ使ってみて実感してみください。