プログラミングの継承とは、遺伝子の引き継ぎである

308, 2020-02-24

目次

プログラミングの継承とは?

プログラミングでよく使われている継承とは一体何なのでしょうか?
継承とは、かっこよく言えば「遺伝子の継承」です。
何の遺伝子かと言うと、「クラス」の遺伝子です。

  • クラスの遺伝子の継承

この記事ではまずクラスとは何なのかを解説し、それに続いて継承とは何なのかを解説していきます。
ポイントは↓の通りです。

  • クラスとは?
  • メンバ変数とメソッドとは?
  • クラスの継承

クラスとは?

まず最初にクラスについてです。
継承とは、クラスを使うときに使われる概念です。
つまり「継承を使う=クラスを使う」とほぼ同義です(クラスは使っても、継承は使わないときもあります)。

クラスは簡単に言うと、データそのデータを扱う関数をひとつにまとめたものです。

動物のデータの扱い

たとえば動物図鑑プログラムを作っていたとします。
そのプログラムの中で動物の情報を扱う必要が出てきました。
具体的には、動物の名前動物の名前の変更処理が必要になりました。

グローバル変数と関数を使えば、動物の名前と、その名前を変更する関数は↓のような擬似コードにすることができます。

animalName = "タマ"

def setAnimalName(name) {
    global animalName
    animalName = name
}

これはこれで1つの正解ですが、動物が複数になったらどうなるかというと、↓のようになってしまいます。

animal1Name = "タマ"
animal2Name = "ミケ"

def setAnimal1Name(name) {
    global animal1Name
    animal1Name = name
}

def setAnimal2Name(name) {
    global animal2Name
    animal2Name = name
}

これはちょっと不格好ですね。動物が2体ならまだいいですか、10体も20体もいると悲惨なことになります。

動物クラスの誕生

ここで、これらの問題を便利に解決できるのがクラスです。
クラスを使えば動物のデータとそれに関わる関数を1つにまとめることができます。
例えば↓のようにです。

class Animal {
    name = ""

    def setName(name) {
        this.name = name
    }
}

こうして動物を扱うクラス、Animalクラスが生まれました。
クラスを使う場合、動物が増えても安心です。↓のように動物に対応してオブジェクトを作っていけば、複数の動物を量産できるからです。

mike = new Animal()
mike.setName("ミケ")

tama = new Animal()
tama.setName("タマ")
...

ちなみにクラスの中に定義した変数はメンバ変数と言い、関数はメソッドと言います。

クラスの継承とは?

このクラスで使われるのが継承と呼ばれるものです。
先述したとおり、継承とは遺伝子の引き継ぎです。
先程の動物クラスの場合を考えてみましょう。

動物クラスにおける遺伝子とは何なのかと言うと、それはメンバ変数メソッドのことです。
つまり、継承とは「クラスのメンバ変数やメソッドを引き継いで、新しいクラスを作る」ことを指します。

先程の動物クラスの場合を考えてみましょう。

class Animal {
    name = ""

    def setName(name) {
        this.name = name
    }
}

このクラスを引き継いで新しいクラス、例えば猫クラスを作るとしましょう。
猫クラスは↓のようになります。

class Cat extends Animal {
}

この猫クラスは「extends Animal」によって動物クラスを継承しています。
よって、動物クラスで定義されているメンバ変数nameやメソッドsetNameを使うことができます。

mike = new Cat()
mike.setName("ミケ")

これで動物クラスの遺伝子を引き継ぐ猫クラスが誕生しました。

ミケです、よろしく

継承は何の役に立つのか?

ここで疑問になるのが、クラスの継承は一体何の役に立つのか? というところです。
クラスの継承はいろいろな用途に使われますが、その1つが処理の共通化です。

処理の共通化

例えば先程の動物クラスを継承したクラスを、猫クラスの他に犬クラスも作ってみましょう。

class Cat extends Animal {
}

class Dog extends Animal {
}

ここで、すべての動物に「自分の名前を名乗る」という処理を付けることになりました。
この場合、↓のように猫クラスと犬クラスにそれぞれメソッドを定義しても良いのですが、

class Cat extends Animal {
    def sayName() {
        printf("%sだよ\n", this.name)
    }
}

class Dog extends Animal {
    def sayName() {
        printf("%sだよ\n", this.name)
    }
}

これは、同じ処理が2つあって明らかに無駄です。
よってこれは、動物クラスの方に実装します。

class Animal {
    name = ""

    def sayName() {
        printf("%sだよ\n", this.name)
    }
}

そして、猫クラスと犬クラスの方は先程のように空っぽのクラスにしておきます。

class Cat extends Animal {
}

class Dog extends Animal {
}

こうするとどうなるかというと、動物クラスを継承している猫クラスと犬クラスは、動物クラスのsayNameメソッドを使うことが出来るのです。
よって↓のようにしても大丈夫なわけですね。

cat = new Cat()
cat.sayName()

dog = new Dog()
dog.sayName()

これでsayNameという名前を名乗らせるメソッドを共通化することができました。
猫クラスと犬クラスには手を加えずに、機能を拡張することができたわけです。

継承の難しさ

ここで注意したいのが、何でもかんでもすぐにクラスを継承して、処理を共通化するのはよくないということです。
無計画な継承はいわゆる神クラスを登場させ、プロジェクトの管理を難しくします。
継承は便利な半面、危険な副作用も持ち合わせているわけですね。

そのため比較的に最近になって登場した言語、たとえばGoなどはデフォルトで継承という機能を使えなくしています。
果たしてそれが正解なのかどうかは、言語設計者の思想によって違うのですが、まぁ継承はメリットばかりではないという証拠ですね。

おわりに

いかがでしたでしょうか。
継承は便利な機能ですが、別に使わなくても困ることは少ない機能です。
最近のプログラミングでは継承の持つデメリットに注目が集まりがちですが、この機会に継承を本当に使うべきかどうか検討してみるのも良いかもしれません。
ちなみに継承を使わない場合は委譲コンポジションというアイデアを使うことも出来るので、それについても調べてみてください。

継承は計画的に

おしまい

Webアプリケーションの制作ならNARUPORT

Webアプリケーションの制作ならNARUPORTにお任せください。
Webアプリの他にもGUIアプリやChromeExtension, スクリプトの制作など可能です。
以下のお問い合わせフォームからご依頼ください!

投稿者名です。64字以内で入力してください。

必要な場合はEメールアドレスを入力してください(全体に公開されます)。

投稿する内容です。

スポンサーリンク

スポンサーリンク

スポンサーリンク

スポンサーリンク