ユーニックス総合研究所

  • home
  • archives
  • programming-extends

プログラミングの継承についてわかりやすく解説してみた

プログラミングにおける継承とは?

現代的なプログラミング言語を学んでいると、かならずこのワードが教材の中に出てきます。
それは「継承」です。
継承とは、オブジェクト指向における考え方の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クラスを継承しています。
そしてメンバ変数(属性)であるnamevoiceの値をちょちょいといじってます。
say()メソッドはそのままAnimalクラスのものを使っています。

このように継承を使うと簡単にクラスの機能を引き継ぐことが出来ます。

🦝 < 便利ですね

おわりに

今回はプログラミングにおける継承について見て見ました。
継承は便利ですが、その扱いはなかなか悩ましいものです。
みなさんもぜひ使ってみて実感してみください。