【Kotlin】レッスン5-7:クラスの継承を基礎から理解しよう

ながみえ

一つ前のページでは静的メンバとインスタンスメンバについて学習しました。

今回は クラスの継承 について見ていきましょう。

Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:関数編
Lesson4:コレクション編
Lesson5:オブジェクト指向編

 ・Lesson5-1:クラスの基本を理解しよう
 ・Lesson5-2:プライマリコンストラクタを理解しよう
 ・Lesson5-3:セカンダリコンストラクタを理解しよう
 ・Lesson5-4:ふたつのコンストラクタを使いこなそう
 ・Lesson5-5:アクセス修飾子とカプセル化を理解しよう
 ・Lesson5-6:静的メンバとインスタンスメンバを理解しよう
 ・Lesson5-7:クラスの継承を理解しよう ◁今回はココ
 ・Lesson5-8:メソッドのオーバーライドを理解しよう
 ・Lesson5-9:クラスを拡張しよう
 ・Lesson5-10:抽象クラスを理解しよう
 ・Lesson5-11:インターフェースを理解しよう
 ・Lesson5-12:データクラスを理解しよう
 ・確認問題5-☆1:モンスター捕獲ゲームを作ろう
 ・確認問題5-☆2:マルバツゲームを作ろう
 ・確認問題5-☆3:石取りゲームを作ろう

<<前のページ

学習記事一覧

次のページ>>

クラスの継承とは何か?基礎から仕組みを解説

プログラムを効率よく設計・開発するために、Kotlinでは「クラスの継承」という仕組みがあります。

本記事では「継承」が何なのか、その基本構文や具体例を通して、初心者の方でも理解できるように解説していきます。

クラスの継承とは何か?|意味と役割と基本構文

クラスの継承 とは既存のクラス(親クラス)の特徴や機能を新しいクラス(子クラス)が引き継ぐ仕組みです。

これにより同じような機能を持つクラスを効率的に作成できるため、コードの再利用性が向上し、開発の手間を大幅に削減できます。

Kotlinでは、open修飾子 を用いて親クラスを定義し、コロン(:) を用いて子クラスに継承します。

クラスを継承する際の基本構文は以下の通りです。

// 親クラス(スーパークラス)
open class 親クラス名 { // 親クラスの定義
    // 継承させたい共通機能
    }
}

// 子クラス(サブクラス)
class 子クラス名 : 親クラス名 { // 親クラスを継承した子クラスの定義
	// 子クラスの独自機能
}

これにより、子クラス側で親クラスの機能を使用する準備が出来ました。

クラスの継承の使用コード例と使用するメリット

次に上記の構文を使った具体例を見てみましょう。

open class Animal(val name: String) {		// 親クラスとして使用するAnimalクラスの定義
    fun eat() {								// Animalクラスのインスタンスメソッド
        println("$name is eating.")
    }
}
class Dog(name: String) : Animal(name) {	// Animalクラスを継承したDogクラスの定義
    fun bark() {							// Dogクラスのインスタンスメソッド
        println("$name is barking.")
    }
}
fun main(){
  val dog = Dog("Rex")  // インスタンス生成
  dog.eat()				// 親クラスのメソッドを呼び出し
  dog.bark()			// 子クラスのメソッドを呼び出し
}

このコードでは「Rex」という名前の犬を表すDogオブジェクトを作成しています。

DogオブジェクトはAnimalクラスを継承しているので、Animalクラスののeat()メソッドも使用できます。

継承を使うことで得られる主なメリットは以下の通りです:

  • コードの再利用性向上:共通の機能を親クラスにまとめることで、子クラスで再定義する必要がなくなります。
  • コードの保守性向上:親クラスを修正するだけで、関連するすべての子クラスに変更が反映されます。
  • 設計の簡略化:複雑なクラスの関係を簡潔に整理できます。

まとめ|クラス継承のポイントを押さえよう

クラスの継承は、既存のクラスの機能を再利用しつつ、新しい機能や独自のふるまいを追加できる強力な仕組みです。

継承の仕組みを正しく理解し、状況に応じて親クラス・子クラスを適切に使い分けることで、コードの再利用性や保守性を高めることができます。

今回学んだポイントを活かして、より柔軟で拡張性の高いクラス設計にチャレンジしてみましょう。

練習問題|クラス継承を使って犬と猫を表現しよう

Kotlinの「クラスの継承」を理解するために、動物のクラスをベースに犬と猫のクラスを作成するプログラムを作りましょう。

このプログラムでは、動物の基本的な情報を管理するAnimalクラスを定義し、そのAnimalクラスを継承したDogクラスとCatクラスを作成します。

これにより、犬と猫の名前を表示し、それぞれの鳴き声をコンソールに表示するプログラムを完成させます。

この問題の要件

以下の要件に従ってコードを完成させてください。

  • Animalという名前のクラスを作成し、nameという名前のプロパティを持たせること。このプロパティはコンストラクタを使用して初期化します。
  • Animalクラスに、動物の名前を表示するdisplayInfoという関数を作成すること。この関数では、nameプロパティの値を使用して、「動物の名前: [name]」という形でコンソールに出力します。
  • Animalクラスを継承したDogクラスを作成し、Dogクラスに犬の鳴き声を表示するbarkという関数を定義すること。この関数では、「[name] はワンワンと鳴いています。」とコンソールに出力します。
  • 同様に、Animalクラスを継承したCatクラスを作成し、Catクラスに猫の鳴き声を表示するmeowという関数を定義すること。この関数では、「[name] はニャーニャーと鳴いています。」とコンソールに出力します。
  • main関数を作成し、DogクラスとCatクラスのインスタンスを作成すること。それぞれに適切な名前を与え、displayInfo関数と鳴き声を表示する関数を呼び出して、結果をコンソールに出力すること。

ただし、以下のような実行結果となること。

動物の名前: ポチ
ポチ はワンワンと鳴いています。
動物の名前: タマ
タマ はニャーニャーと鳴いています。

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

Q
ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。

1:Animalクラスの定義
  □ プライマリコンストラクタでnameプロパティを初期化
  □ displayInfoメソッドの定義
    □ 動物の名前を出力する処理
2:Dogクラスの定義(Animalクラスを継承)
  □ プライマリコンストラクタでnameプロパティを初期化
  □ barkメソッドの定義
    □ 犬の鳴き声を出力する処理
3:Catクラスの定義(Animalクラスを継承)
  □ プライマリコンストラクタでnameプロパティを初期化
  □ meowメソッドの定義
    □ 猫の鳴き声を出力する処理
4:main関数の定義
  □ Dogクラスのインスタンスを作成し、変数dogに代入
  □ Catクラスのインスタンスを作成し、変数catに代入
  □ dog.displayInfoメソッドを呼び出し、犬の名前を出力
  □ dog.barkメソッドを呼び出し、犬の鳴き声を出力
  □ cat.displayInfoメソッドを呼び出し、猫の名前を出力
  □ cat.meowメソッドを呼び出し、猫の鳴き声を出力

Q
ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

// Animalクラスを定義
open class Animal(val name: String) {
    // 名前を表示する関数
    fun displayInfo() {
        /* 【穴埋め問題1】
        ここにnameプロパティを使用して、動物の名前を表示するコードを書いてください。
        例: println("動物の名前: $name")
        */
    }
}

// DogクラスをAnimalクラスから継承
class Dog(name: String) : Animal(name) {
    // 犬の鳴き声を表示する関数
    fun bark() {
        /* 【穴埋め問題2】
        ここにnameプロパティを使用して、犬の鳴き声を表示するコードを書いてください。
        例: println("$name はワンワンと鳴いています。")
        */
    }
}

// CatクラスをAnimalクラスから継承
class Cat(name: String) : Animal(name) {
    // 猫の鳴き声を表示する関数
    fun meow() {
        /* 【穴埋め問題3】
        ここにnameプロパティを使用して、猫の鳴き声を表示するコードを書いてください。
        例: println("$name はニャーニャーと鳴いています。")
        */
    }
}

fun main() {
    // Dogクラスのインスタンスを作成
    /* 【穴埋め問題4】
    ここにDogクラスのインスタンスを作成するコードを書いてください。
    例: val dog = Dog("ポチ")
    */
    
    // Catクラスのインスタンスを作成
    /* 【穴埋め問題5】
    ここにCatクラスのインスタンスを作成するコードを書いてください。
    例: val cat = Cat("タマ")
    */
    
    // 犬の名前を表示
    /* 【穴埋め問題6】
    ここにdogインスタンスのdisplayInfo関数を呼び出すコードを書いてください。
    例: dog.displayInfo()
    */

    // 犬の鳴き声を表示
    /* 【穴埋め問題7】
    ここにdogインスタンスのbark関数を呼び出すコードを書いてください。
    例: dog.bark()
    */
    
    // 猫の名前を表示
    /* 【穴埋め問題8】
    ここにcatインスタンスのdisplayInfo関数を呼び出すコードを書いてください。
    例: cat.displayInfo()
    */
    
    // 猫の鳴き声を表示
    /* 【穴埋め問題9】
    ここにcatインスタンスのmeow関数を呼び出すコードを書いてください。
    例: cat.meow()
    */
}

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

この問題の解答と解説

この問題の正解コードとその解説は以下の通りです。

クリックして開いて確認してください。

Q
正解コード
// Animalクラスを定義
open class Animal(val name: String) {
    // 名前を表示する関数
    fun displayInfo() {
        println("動物の名前: $name")
    }
}

// DogクラスをAnimalクラスから継承
// クラスの継承により、Animalクラスのプロパティとメソッドを引き継ぎます
class Dog(name: String) : Animal(name) {
    // 犬の鳴き声を表示する関数
    fun bark() {
        println("$name はワンワンと鳴いています。")
    }
}

// CatクラスをAnimalクラスから継承
// Dogクラスと同様に、Animalクラスのプロパティとメソッドを引き継いでいます
class Cat(name: String) : Animal(name) {
    // 猫の鳴き声を表示する関数
    fun meow() {
        println("$name はニャーニャーと鳴いています。")
    }
}

fun main() {
    // Dogクラスのインスタンスを作成
    // Animalクラスのプロパティnameは、Dogクラスのインスタンス作成時に初期化されます
    val dog = Dog("ポチ")
    // Catクラスのインスタンスを作成
    // 同様に、Animalクラスのプロパティnameが初期化されます
    val cat = Cat("タマ")

    // 犬の名前を表示
    // 継承したdisplayInfoメソッドを使用しています
    dog.displayInfo()
    // 犬の鳴き声を表示
    dog.bark()

    // 猫の名前を表示
    // 同様に、継承したdisplayInfoメソッドを使用しています
    cat.displayInfo()
    // 猫の鳴き声を表示
    cat.meow()
}
Q
正解コードの解説

コードをブロックごとに分割して解説しますそれぞれのクラスや関数の役割について解説します。

Animalクラスの定義

open class Animal(val name: String) {
    fun displayInfo() {
        println("動物の名前: $name")
    }
}
  • open class Animal(val name: String): Animalクラスは動物を表すクラスです。nameという名前のプロパティを持ち、nameはインスタンス化されるときに初期化されます。openキーワードは、このクラスが他のクラスから継承されることを意味します。
  • fun displayInfo(): この関数は、動物の名前を表示します。println関数を使って、nameプロパティの値を出力します。

Dogクラスの定義

class Dog(name: String) : Animal(name) {
    fun bark() {
        println("$name はワンワンと鳴いています。")
    }
}
  • class Dog(name: String) : Animal(name): DogクラスはAnimalクラスを継承しています。つまり、Animalクラスのプロパティやメソッドをそのまま利用できます。
    nameプロパティはAnimalクラスから継承され、コンストラクタで初期化されます。
  • fun bark(): Dogクラスに特有の関数で、犬の鳴き声を出力します。nameプロパティを使用して、具体的な犬の名前と鳴き声を出力します。

Catクラスの定義

class Cat(name: String) : Animal(name) {
    fun meow() {
        println("$name はニャーニャーと鳴いています。")
    }
}
  • class Cat(name: String) : Animal(name): CatクラスもAnimalクラスを継承しています。これにより、Animalクラスのプロパティやメソッドを利用できます。
  • fun meow(): Catクラスに特有の関数で、猫の鳴き声を出力します。nameプロパティを使用して、猫の名前と鳴き声を出力します。

main関数の定義

fun main() {
    val dog = Dog("ポチ")
    val cat = Cat("タマ")
    
    dog.displayInfo()
    dog.bark()
    
    cat.displayInfo()
    cat.meow()
}
  • cat.displayInfo()cat.meow(): Catインスタンスであるcatの名前を表示し、続けて鳴き声を表示します。
  • val dog = Dog("ポチ"): Dogクラスのインスタンスを作成し、ポチという名前を与えます。このとき、Animalクラスのnameプロパティがポチに初期化されます。
  • val cat = Cat("タマ"): Catクラスのインスタンスを作成し、タマという名前を与えます。このとき、Animalクラスのnameプロパティがタマに初期化されます。
  • dog.displayInfo()dog.bark(): Dogインスタンスであるdogの名前を表示し、続けて鳴き声を表示します。
Q
サイト改善アンケート & ご指摘/ご質問

本サイトでは、みなさまの学習をよりサポートできるサービスを目指しております。
そのため、みなさまの「プログラミングを学習する理由」などを アンケート 形式でお伺いしています。

また記事の内容に関する ご指摘ご質問 もお待ちしています。

1.このサイトをどのように活用していますか?また、今後どのように活用したいですか?
5.気になっているサービス・商品があれば教えてください。
※ 特定の記事に関する内容の場合は、記事番号(レッスン〇-〇)をご記入願います。

<<前のページ

学習記事一覧

次のページ>>

記事URLをコピーしました