質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Swift Playground

Swift Playgroundは、Swiftをインタラクティブに習得できるiPad向けのアプリケーション。コーディングの知識は一切必要なく、Swift Playgrounds上でプログラミングしたコードによりドローン・ロボットを自在に動かすことが可能です。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

3回答

561閲覧

Swift  イニシャライザの自動的な継承について

moriman

総合スコア615

Swift Playground

Swift Playgroundは、Swiftをインタラクティブに習得できるiPad向けのアプリケーション。コーディングの知識は一切必要なく、Swift Playgrounds上でプログラミングしたコードによりドローン・ロボットを自在に動かすことが可能です。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

1クリップ

投稿2020/01/30 03:53

https://docs.swift.org/swift-book/LanguageGuide/Initialization.html

Swift

1class Food { 2 var name: String 3 init(name: String) { 4 self.name = name 5 } 6 convenience init() { 7 self.init(name: "[Unnamed]") 8 } 9} 10 11class RecipeIngredient: Food { 12 var quantity: Int 13 init(name: String, quantity: Int) { 14 self.quantity = quantity 15 super.init(name: name) 16 } 17 override convenience init(name: String) { 18 self.init(name: name, quantity: 1) 19 } 20} 21 22class ShoppingListItem: RecipeIngredient { 23 var purchased = false 24 var description: String { 25 var output = "(quantity) x (name)" 26 output += purchased ? " ✔" : " ✘" 27 return output 28 } 29} 30 31var breakfastList = [ 32 ShoppingListItem(), 33 ShoppingListItem(name: "Bacon"), 34 ShoppingListItem(name: "Eggs", quantity: 6), 35] 36breakfastList[0].name = "Orange juice" 37breakfastList[0].purchased = true 38for item in breakfastList { 39 print(item.description) 40} 41// 1 x Orange juice ✔ 42// 1 x Bacon ✘ 43// 6 x Eggs ✘

上記のSwiftドキュメントページのイニシャライザについてなんですが、イニシャライザの継承の挙動について、
混乱しています。

ShoppingListItemクラスには自身のプロパティ(purchased)にデフォルト値があり、
指定イニシャライザを定義していないので、スーパークラスであるRecipeIngredientの
指定イニシャライザ・コンビニエンスイニシャライザを継承する、ということで
breakfastList[2]で考えてみます。

ShoppingListItem(name: "Eggs", quantity: 6)
が実行されると、ShoppingListItemが継承した、RecipeIngredientの指定イニシャライザが呼び出されるのだと思います。
継承したRecipeIngredientの指定イニシャライザは、

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

↑な訳ですが、継承しているので、上記のselfは、ShoppingListItemにとってのself、つまりShoppingListItem
上記のsuperはShoppingListItemにとってのsuper、つまりRecipeIngredient
というのが現在の認識なのですが、
そうすると、上記の

super.init(name:name)

は、RecipeIngredientのinit(name:name)、つまりRecipeIngredientのコンビニエンスイニシャライザが呼び出される、ということになり、そうするとquantityプロパティに1がセットされる訳ですが、
非常に複雑で訳がわからない(辻褄が合わない)し、結果を見ても違うようです。

ただ、これの一つ前の、RecipeIngredientクラスがFoodクラスのコンビニエンスイニシャライザを継承する説明では
やはり上記のように考えているようなので、ShoppingListItemのイニシャライザの継承はどう考えれば良いのかわからない状態です。

多分何か勘違いしているのだと思うのですが、どう考えれば良いでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

難しく考えすぎです。

swift

1class RecipeIngredient: Food { 2 var quantity: Int 3 init(name: String, quantity: Int) { 4 self.quantity = quantity // このselfはRecipeIngredientのインスタンスです 5 super.init(name: name) // このsuperはRecipeIngredientのスーパークラス。つまりFoodです。 6 } 7 override convenience init(name: String) { 8 self.init(name: name, quantity: 1) 9 } 10}

コメントの通りです。
これは継承などとは関係なく変わることはありません。

では、このselfShoppingListItemのイニシャライズ時はどうなるか。
ShoppingListItemのインスタンスはRecipeIngredientのインスタンスでもあります。継承関係にあるためShoppingListItemRecipeIngredientを内包しているからです。
ですので、このselfは初期化されようとするShoppingListItemのインスタンスのことです。

ShoppingListItemのインスタンスがRecipeIngredientのインスタンスでもあるということは

swift

1let a: RecipeIngredient = ShoppingListItem(name: "a")

が問題なくコンパイルできることから確認できます。

投稿2020/02/01 02:34

MasakiHori

総合スコア3384

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

継承しているので、上記のselfは、ShoppingListItemにとってのself、つまりShoppingListItem
上記のsuperはShoppingListItemにとってのsuper、つまり>RecipeIngredient
というのが現在の認識なのですが、

前半はOKですが、後半は違っていると思います。

継承しているので、selfはご理解のとおりに変わります。

しかし、継承しても、superの型は変わりません。

ShoppingListItemとして生成したオブジェクトであっても、RecipeIngredient.init(name:)の中でのsuperは、Food型を指していて、RecipeIngredient型を指すように変わるわけではありません。
したがって、ここでのsuper.init(name:)は、Food.init(name:)を呼びます。

投稿2020/01/30 05:44

eytyet

総合スコア803

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moriman

2020/01/30 06:02

回答を頂きましてありがとうございます。 お示し頂いた考え方で辻褄が合うと思いますので、多分そうなんだと思いますが、 「継承した場合selfが指す物は変わるが、superが指す物は変わらない」 というのは、公式ドキュメントで説明されている箇所はありますでしょうか?
eytyet

2020/01/30 07:27 編集

探してみましたが、明示的にsuperが指す物はかわらない、という記述は見当たりませんでした。言い方が正しく無いのかもしれませんね。むしろselfが変わるという言い方が間違いかな・・・ Inheritanceの章に、クラスはメソッド、プロパティ、サブスクリプトをオーバーライドできると書いてあります。親クラスをオーバーライドできるとは書いてありません。継承により、親クラスのコードであっても子クラスのメソッドを呼ぶようにできるのはオーバーライドによるものなので、オーバーライドできないsuperを自分のものに置き換えることはできない、と理解するべきなのかもしれませんね。 実際にsuperを使うときは、親クラスで実装済みの機能を再利用するために呼びます。そのクラスの上位以外のsuperが呼ばれたら意図しない動作になるので使えません。
guest

0

ShoppingListItem(name: "Eggs", quantity: 6)

が実行されると、ShoppingListItemが継承した、RecipeIngredientの指定イニシャライザが呼び出されるのだと思います。

ShoppingListItem のイニシャライザが定義されていない場合、サブクラスのイニシャライザを自動的に継承するので、その通りかと思います。

継承しているので、上記のselfは、ShoppingListItemにとってのself、つまりShoppingListItem

上記のsuperはShoppingListItemにとってのsuper、つまりRecipeIngredient
というのが現在の認識

この認識が違います。オーバーライドしているのではなく、継承したメソッドなので、RecipeIngredientがselfという認識になります。

普通に以下のようなコードを考えた際に、descriptionメソッドを継承したBicycleがdescriptionメソッドを読んだ場合、Vehicleで定義したdescriptionが呼ばれるのと同じです。

swift

1class Vehicle { 2 func description() -> String { 3 return "traveling at (currentSpeed) miles per hour" 4 } 5} 6class Bicycle: Vehicle { 7 var hasBasket = false 8} 9let bicycle = Bicycle() 10let desc = bicycle.description()

投稿2020/01/30 05:01

t_obara

総合スコア5488

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moriman

2020/01/30 05:36

回答をいただきましてありがとうございます。 お示し頂きましたコードなのですが、Vehicleクラスに初期化したプロパティを宣言するか、イニシャライザを 定義するかしないとエラーが出るので、プロパティを宣言して、 class Vehicle { var currentSpeed=0.0 func description() -> String { return "traveling at (currentSpeed) miles per hour" } } class Bicycle: Vehicle { var hasBasket = false } let bicycle = Bicycle() let desc = bicycle.description() print(desc) //traveling at 0.0 miles per hour 上記のように表示されるのですが、この結果で、Bicycleのdescriptionではなく、 Vehicleのdescriptionが呼び出された、と確認できますでしょうか? Bicycleのdescriptionが呼び出されても結局同じ表示になるような気がするのですが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問