[Swift] クラスのイニシャライザ４： override 修飾子

# はじめに

この記事では、override 修飾子について説明します。


# 他の記事へのリンク

* [[Swift] クラスのイニシャライザ１： イニシャライザの引数の書き方](http://qiita.com/cotrpepe/items/bfebe21e9f75c1fce60c)
* [[Swift] クラスのイニシャライザ２： プロパティの初期化方法](http://qiita.com/cotrpepe/items/db842f74b4c8ce16052c)
* [[Swift] クラスのイニシャライザ３： Designated Initializer と Convenience Initializer](http://qiita.com/cotrpepe/items/3052d91468f1b852582a)
* [[Swift] クラスのイニシャライザ４： override 修飾子](http://qiita.com/cotrpepe/items/8d197a9a288eb24c19fb)
* [[Swift] クラスのイニシャライザ５： required 修飾子](http://qiita.com/cotrpepe/items/3931c0c20ef43f4a18ac)
* [Swift] クラスのイニシャライザ６： Failable Initializer


# 環境

* Xcode 6.1 (Playground)


# 1. override 修飾子とは？

override 修飾子は、

* スーパークラスのイニシャライザをサブクラスのイニシャライザでオーバーライドするとき

に使います。

```swift
class Animal {
    let name: String
    
    //
    // A
    //
    init(name: String) {
        self.name = name
    }
}

class Cat: Animal {
    //
    // スーパークラスの A をオーバーライドする
    //
    override init(name: String) {
        super.init(name: name + "!!")
    }
}

var c = Cat(name: "kitty")
println(c.name) // -> kitty!!
```


# 2. override 修飾子の書き方

## 2.1. Designated initializer の場合

```swift
override init() {
    ...
}
```

## 2.2.  Convenience initializer の場合

```swift
override convenience init() {
    ...
}
```


# 3. オーバーライドができる条件

オーバーライドできるのは、以下の２つの条件が満たされている場合のみです。

* 条件１） スーパークラスとサブクラスのイニシャライザが「同じイニシャライザ」である
* 条件２） オーバーライドされる側が designated initializer である


## 条件１） スーパークラスとサブクラスのイニシャライザが「同じイニシャライザ」である

「同じイニシャライザ」とは、「引数の型、数、名前が同じ」という意味です。引数名も同一である必要があるので注意しください。

例えば、以下の A と B のイニシャライザは、引数の型と数が同じですが、第一引数の名前が異なっています（name と nickname）。そのため、「同じイニシャライザ」ではないので、オーバーライドできません。

```swift:A
class Animal {
    init(name: String, age: Int) {
        ...
    }
}
```

```swift:B
class Cat: Animal {
    init(nickname: String, age: Int) {
        ...
    }
}
```

## 条件２） オーバーライドされる側が designated initializer である

### 例１） Designated -> Designated の場合

![override_d2d.png](https://qiita-image-store.s3.amazonaws.com/0/46434/587a9630-f6b0-d163-3d2b-2c1e95d804e2.png)

```swift
class Animal {
    var name: String
    
    //
    // A
    //
    init() {
        self.name = "unknown"
    }
}

class Cat: Animal {
    //
    // A をオーバーライド -> OK
    //
    override init() {
        super.init()
        self.name = "kitty"
    }
}

var c = Cat()
println(c.name) // -> kityy
```

### 例２） Convenience -> Designated の場合

![override_c2d.png](https://qiita-image-store.s3.amazonaws.com/0/46434/97f2eb6d-b6af-b66a-6a57-52ffa6a93821.png)

```swift
class Animal {
    var name: String
    
    //
    // A
    //
    init() {
        self.name = "unknown"
    }
}

class Cat: Animal {
    //
    // A をオーバーライド -> OK
    //
    override convenience init() {
        //
        // スーパークラスから自動的に継承された A を呼び出す（下記の「注意１」「注意２」を参照）
        //
        self.init()
        self.name = "kitty"
    }
}

var c = Cat()
println(c.name) // -> kityy
```

#### 注意１）

```self.init()``` では、スーパークラスから自動的に継承されたイニシャライザを呼び出しています。

詳細は、以下の記事を参照してください。

* [[Swift] クラスのイニシャライザ３： Designated Initializer と Convenience Initializer](http://qiita.com/cotrpepe/items/3052d91468f1b852582a) の「9. イニシャライザの自動的な継承」


#### 注意２） 

オーバーライドをしている場合でも、convenience initializer の中では、スーパークラスのイニシャライザを呼び出せないことに注意してください。

詳細は、以下の記事を参照してください。

* [[Swift] クラスのイニシャライザ３： Designated Initializer と Convenience Initializer](http://qiita.com/cotrpepe/items/3052d91468f1b852582a) の「6. Convenience Initializer は同じクラスのイニシャライザを呼び出すことができる」


### 例３） Designated -> Convenience の場合

![override_d2c.png](https://qiita-image-store.s3.amazonaws.com/0/46434/a6a34fac-4222-ef99-a879-658b4deb0698.png)

```swift
class Animal {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    //
    // A
    //
    convenience init() {
        self.init(name: "unknown")
    }
}

class Cat: Animal {
    //
    // A をオーバーライド -> NG
    //
    override init() { // ->  error: initializer does not override a designated initializer from its superclass
    }
}
```

### 例４） Cesignated -> Convenience の場合

![override_c2c.png](https://qiita-image-store.s3.amazonaws.com/0/46434/3afee216-b40f-7e00-0e9e-bd6e8dcb8dd2.png)

```swift
class Animal {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    //
    // A
    //
    convenience init() {
        self.init(name: "unknown")
    }
}

class Cat: Animal {
    //
    // A をオーバーライド -> NG
    //
    override convenience init() { // ->  error: initializer does not override a designated initializer from its superclass
        self.init(name: "unknown!!")
    }
}
```


# 4. 例

## 例１） スーパークラスに Default Initializer があるパターン

```swift
class Animal {
    var name: String = "unknown"
    
    //
    // 全てのプロパティにデフォルト値が設定されているので、
    // default initializer "init() {}" が暗黙的に実装される
    //
}

class Cat: Animal {
    //
    // スーパークラスの default initializer をオーバーライド
    //
    override init() {
        super.init()
        self.name = "kitty"
    }
}

var c = Cat()
println(c.name) // -> kitty
```

## 例２） スーパークラスにイニシャライザが自動的に継承されているパターン

```swift
class Animal {
    var name: String
    
    //
    // A
    //
    init(name: String) {
        self.name = name
    }
}

class Cat: Animal {
    //
    // Designated initializer が１つも実装されていないので、
    // スーパークラス Animal から A が自動的に継承される（下記の「補足」を参照）
    //
}

class PersianCat: Cat {
    //
    // A をオーバーライド
    //
    override init(name: String) {
        super.init(name: name)
    }
}

var c = Cat(name: "kitty")
println(c.name) // -> kityy
```

### 補足）

イニシャライザの自動的な継承については、以下の記事を参照してください。

* [[Swift] クラスのイニシャライザ３： Designated Initializer と Convenience Initializer](http://qiita.com/cotrpepe/items/3052d91468f1b852582a) の「9. イニシャライザの自動的な継承」


# 参考文献

[The Swift Programming Language](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_306)