Swiftにおけるクラスの概念


Swiftにおけるクラスの概念

今回はオブジェクト指向におけるクラスの概念です。(特にSwiftを中心とした説明です)
間違いもあると思うので参考程度にしてください。また、ミスがあればこっそりと教えてください。

1. クラスとは?


クラスとは簡単に言えば「設計図」です。クラスにはメソッドや変数と呼ばれる要素が含まれています。クラスを使うことによって、オブジェクトのデータを共通のフォーマットで管理できる為、データの管理が簡単になります。

Swiftではクラスを下記のように宣言します。

class MonsterController {
var name: String?
   var level: Int?
   var hp: Int?
}

クラス名は一般的に最初の1文字を大文字にする「アッパーキャメル」という書式で記述します。

2. インスタンス化

クラスはオブジェクトの内容を定義する設計図みたいなものです。実際にクラスを利用するにはインスタンス化(実体化)する必要があります。設計図から製品を実際に作るイメージです。インスタンスを生成するには、次のようにクラス名に( )を付けて関数のように宣言します。

var monster = MonsterController()

インスタンスを生成したら、メンバ変数(インスタンス変数)やメソッド(クラスの関数をメソッドと呼びます。)にアクセスできます。
これらインスタンスの属性には、インスタンス名の後に.(ドット)をつけてアクセスします。

monster.name = "Bear"
monster.hp = 1000

別のインスタンスを生成することもできます。

var slime = MonsterController()
slime.name = "King"
monster.hp = 800

3. イニシャライザ

インスタンスの生成時に必ず実行されるメソッドを定義して、その中で変数の初期化を行うことができます。このメソッドをイニシャライザ、又はコンストラクタと呼びます。
イニシャライザは、initという名前のメソッドです。但しメソッド名の前にfuncを書く必要はありません。

class Monster {
    let name: String
    var level: Int
    var hp: Int
    // イニシャライザ
    init() {
        self.name = "不明"
        self.level = 1
        self.hp = 500
    }
}

selfは自分自身(インスタンス)を指し、そのインスタンスの属性であることを示すために使用しますが、上の場合はnameはメンバ変数であることが明確なので無くても構いません。

非オプショナル型の変数(?, !がない型)は、上のように宣言時に値を設定するか、イニシャライザの中で初期値を与える必要があります。(初期値を与えないとコンパイルエラーになります。)

イニシャライザには次のように引数(外部から与えられるデータ)を与えることができます。引数はインスタンスの生成時に渡します。また、特に指定しない限りローカル引数名が外部名となります。

class Monster {
    let name: String
    var level: Int

    init(name: String, level: Int = 1) {
        self.name = name
        self.level = level
    }
}

let slime = Monster(name: "スライムB", level: 5)   //スライム level 5

上の場合、メンバ変数の名前とイニシャライザの引数の名前が同じなので、selfを使ってメンバ変数と引数を区別する必要があります。(selfをつけないと優先的に引数と認識されます。)

4. オーバーロード

オーバーロードとは、メソッド名は同じだが引数の数が異なるメソッドを宣言することです。(後に記述する「オーバーライト」と名前が似ているので間違わないように)

class Monster {
    let name: String
    var level: Int

    // 引数が1つ
    init(name: String) {
        self.name = name
        self.level = 5
    }

    // 引数が2つ
    init(name: String, level: Int = 1) {
        self.name = name
        self.level = level
    }
}

//引数が1つのイニシャライザが呼ばれる
let slimeA = Monster(name: "スライムA")   //スライムA level 5

//引数が2つのイニシャライザが呼ばれる
let slimeB = Monster(name: "スライムB", level: 3)   //スライムB level 3

インスタンス化するときに与える引数の数を変えることにより、Monsterクラスで呼ばれるイニシャライザが異なります。このように引数の数だけを変えたものを「オーバーロード」と呼びます。

5. 継承

クラスには継承という考え方があります。継承元のクラスをスーパークラスと呼び、継承したクラスをサブクラスと呼びます。継承するとサブクラスにはスーパークラスで宣言されたすべてのオブジェクトとメソッドが使えるようになります。


                図1 クラス(継承)のイメージ図

Swiftでは下記のように宣言する。
"サブクラス名:(コロン) スーパークラス名"

// Monsterクラス
class Monster {
    var name: String
    var level: Int

    init(name: String, level: Int) {
        self.name = name
        self.level = level
    }

    func attackMonster(enemy: Monster) {
        print("\(self.name)\(enemy.name)を攻撃した。");
    }
}

/* Slimeクラス(Monsterクラスを継承) */
class Slime: Monster {
    func escapeFromMonster(enemy: Monster) {
        print("\(self.name)\(enemy.name)から逃げた。");
    }
}

let monster = Monster(name: "モンスター", level:3)
let slime = Slime(name: "スライム", level:2)
monster.atackMonster(slime)        // モンスターはスライムを攻撃した。
slime.atackMonster(monster)        // スライムはモンスターを攻撃した。
slime.escapeFromMonster(monster)   // スライムはモンスターから逃げた。

上の例はMonsterクラスを継承したSlimeクラスを定義したものです。Slimeクラスはインスタンス化した時にイニシャライザが呼ばれますが、Slimeクラスではinitを宣言していないのでスーパークラスであるMonsterクラスのinitが呼ばれます。
スーパークラスのattackMonsterメソッドにはMonsterクラス、Slimeクラスのどちらのオブジェクトからもアクセスできます。

6. オーバーライド

オーバーライドとはスーパークラスとサブクラスで同じ名前の関数を定義することです。

// Monsterクラス
class Monster {
    var name: String
    var level: Int

    init(name: String, level: Int) {
        self.name = name
        self.level = level
    }

    func attackMonster(enemy: Monster) {
        print("\(self.name)\(enemy.name)を攻撃した。");
    }
}

/* Slimeクラス(Monsterクラスを継承) */
class Slime: Monster {
    override func attackMonster(enemy: Monster) {
        print("\(self.name)\(enemy.name)をおちょくった。");
    }
}

let monster = Monster(name: "モンスター", level:3)
let slime = Slime(name: "スライム", level:2)
monster.atackMonster(slime)        // モンスターはスライムを攻撃した。
slime.atackMonster(monster)        // スライムはモンスターをおちょくった。
slime.super.atackMonster(monster)  // スライムはモンスターを攻撃した。

スーパークラスで既に定義されているatackMonsterメソッドをサブクラスで再宣言するにはoverrideをサブクラスの再宣言するメソッドの先頭に記述する必要がある。
SlimeクラスのオブジェクトからスーパークラスのatackMonsterメソッドを呼びたい場合、superを記述することでスーパクラスのメソッドを呼ぶことができます。

以上

June 13, 2016