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

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

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

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

Q&A

解決済

2回答

3263閲覧

スーパークラスを変更するとサブクラスのメンバーが使えない

Blue0999

総合スコア148

Swift

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

0グッド

0クリップ

投稿2016/04/03 03:18

編集2016/04/03 03:22

ContainerViewController: UIViewController

ContainerViewControllerはこのようにUIViewControllerを継承して宣言していますが、ContainerViewControllerの中に宣言されたメソッドで下記のように親クラスを変更したものを変数に代入するとそのインスタンスで親クラスのメンバーには参照できますが子クラスであるContainerViewControllerのプロパティには参照できません。僕は何を勘違いしているのでしょうか?
numは子クラスであるContainerViewController内に定義された整数型のプロパティです。

メソッド {
let parentController = self.parentViewController as! ViewController
parentController.num = 0 // エラー。メンバーにnumは無いと表示。
}

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

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

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

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

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

guest

回答2

0

ベストアンサー

親クラスのメンバーには参照できますが子クラスであるContainerViewControllerのプロパティには参照できません。

コードを見る限り、
let parentController = self.parentViewController as! ViewController
は、親クラス(ViewController)を取得していて
parentController.num = 0
は、親クラス(ViewController)のプロパティを参照しようとして、親クラスにそのようなプロパティはないというエラーになっていると思います。子クラスであるContainerViewControllerのプロパティを参照しているようには見えませんが、何を勘違いしているんでしょうか?

それと、「スーパークラス(UIViewController)を継承したサブクラス(ContainerViewController)」という話と、「親クラス(ViewController)をコンテナとする子クラス(ContainerViewController)」という話は、全く別の話です。タイトルはスーパークラス/サブクラスの話になっているのに、内容はコンテナの親クラス/子クラスの話になっていて、混同されているように見えるので、その点をきちんと区別して理解する必要があるように思います。

投稿2016/04/03 08:00

TakeOne

総合スコア6299

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

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

Blue0999

2016/04/03 08:32 編集

ご回答ありがとうございます! 僕がコードの意味を間違って理解してしまったのかもしれません。 let parentController = self.parentViewController as! ViewController 上記の例でself.parentViewControllerはそのクラスの親クラスを表すので上記はContainerViewControllerの親クラスだけUIViewControllerからViewControllerに変更してparentControllerに代入するのかと思っていたのですが… 間違っている所を教えていただけると嬉しいです!
TakeOne

2016/04/03 09:29 編集

> self.parentViewControllerはそのクラスの親クラスを表すので上記はContainerViewControllerの親クラスだけUIViewControllerからViewControllerに変更してparentControllerに代入する 誤解されている点を指摘できている自信はありませんが、この説明を私がするなら 「self.parentViewControllerは子クラス(ContainerViewController)のコンテナとなる親クラス(ViewController)が格納されているので、上記はContainerViewControllerの親クラス(self.parentViewController)をUIViewControllerからViewControllerにキャストしてparentControllerに代入している」です。 説明に決定的な違いはなく、親クラスをparentControllerに代入して使用するよう説明しており、最初の質問に書かれてある「子クラスであるContainerViewControllerのプロパティには参照できません」ということをしているように見えません。最初の質問とこの補足の説明が同じことを言っているつもりなんですか?
Blue0999

2016/04/03 11:41 編集

補足の説明では説明不足でした。すみません。 改めて書きなおします。          ContainerViewController: UIViewController                    から           ContainerViewController: ViewController                  に変更しものを                変数parentControllerに代入 親クラスは変更されたがContainerViewControllerを代入された事に変わりはない。なのになぜparentControllerからContainerViewControllerに宣言されたプロパティを参照できないのか?という事です。  
TakeOne

2016/04/03 14:42 編集

まず、念のため確認しておきたいのですが、今質問されている画面構成は https://teratail.com/questions/31326 の質問にあるのと同じ構成で、ViewController内に埋め込んだコンテナビューから子ビューコントローラーとしてContainerViewControllerを接続していると思ってよいですか? さらに、以下の説明について確認したいのですが、 >         ContainerViewController: UIViewController >                   から >          ContainerViewController: ViewController >                 に変更しものを >               変数parentControllerに代入 というのは、 let parentController = self.parentViewController as! ViewController の処理内容を説明したものですか? この中で「ContainerViewController: ViewController」の「:」の意味は ContainerViewControllerをViewControllerでキャストするという意味ですか? そして、 self.parentViewControllerにはContainerViewControllerが格納されていると思っていますか? だとしたら、それが認識誤りです。 self.parentViewControllerには親のViewControllerが格納されています。 ただ、self.parentViewControllerはもともとスーパークラスのUIViewControllerとして定義されていますので、親のViewControllerとしてアクセスするためにViewControllerでキャストして参照します。
TakeOne

2016/04/03 15:18

もう一点勘違いしてそうな気がするところがわかったので指摘しておきます。 「親クラスだけ変更する」という言葉です。 今読み直すと、この言葉を 「let parentController = self.parentViewController as! ViewController」 の「as! ViewController」のことを意味したつもりで使っているように見えましたが、 これは、親クラスを変更するという意味ではありません。 指定のクラスにキャストするということです。 キャストの意味がわかってなければ、swiftの入門書等をちゃんと読んで調べてください。 最初の回答で指摘した通り、コンテナの親クラス/子クラスの話と、スーパークラス/サブクラスの継承の話は別の話ですし、 ここで言っている「親クラスを変更する」というのが「スーパークラスを変更する」という意味で使っているのでしたら そもそもそんなことはできません。 オブジェクト指向を理解している人が読んだら、そんなことはできるわけないという前提なので、話が通じないのだと思います。 動物クラスのサブクラスである犬クラスに、今から植物クラスに属してねって言っているようなものですから、めちゃくちゃです。 Odacchiさんも指摘されている通り、やはりオブジェクト指向の考え方ついて一度じっくり勉強する必要があるように思います。
Blue0999

2016/04/04 08:51

教えていただいた内容を完璧に理解する事がまだできません。もう少しプログラムの仕組みを勉強しなおしてから読み返したいと思います。長いことありがとうございました。
guest

0

親クラスの変数に格納すると、親クラスで定義されているメンバ(フィールド、メソッド)しか使えません。
オブジェクト指向の基本です。

---補足追記-----
Animalクラスというクラスがあり、
Animalクラスを継承したHumanクラス、Animalクラスを継承したDogクラスがそれぞれあったとします。
そして、Humanクラスには、仮に、「心(Mind)」というプロパティがあったと仮定しましょう。
(ここで、犬には心がないのかという倫理的or学術的な話は置いといてください。人間のみに心があると仮定します。)

つまり下記のようなクラス定義となるでしょう。

Swift

1Animal { 2 func doSomething() // doSomething()メソッド 3} 4 5Human : Animal { 6 var mind:Mind // mindプロパティ 7 /*以下略*/ 8} 9 10Dog : Animal { 11 /*以下略*/ 12}

今おっしゃってることはHumanクラスのインスタンスをAnimal型の変数に代入しても、mindプロパティを呼び出せるはずという主張です。
では、DogクラスのインスタンスをAnimal型の変数に代入してもmindプロパティを呼び出せるのでしょうか?

Animalクラスとして扱う以上、Animalクラスのメンバ(メソッド、プロパティ)にしかアクセスできないのは、自然なことです。
Animal型の配列にDogとHumanのインスタンス(への参照)を代入して、for文で回してdoSomething()メソッドを呼び出すような使い方ができます(これをポリモーフィズムと言います)が、mindプロパティが呼び出せてしまったら、安全にポリモーフィズムを実現できませんね(dog.mindと呼べるとしたら思わぬ動作orエラーとなるでしょうから)。

Swiftという以前にオブジェクト指向の考え方を一度勉強されてはいかかがでしょうか?
今なら、なぜこう書くのがダメなのかがすっきりすると思います。

投稿2016/04/03 03:47

編集2016/04/03 12:45
Odacchi

総合スコア907

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

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

Blue0999

2016/04/03 04:38

ご回答ありがとうございます! この場合親クラスで変数を宣言したのではなくContainerViewController(サブクラス)のメソッド内で変数を宣言しているのですが…
Odacchi

2016/04/03 12:46

補足追記しました。 簡潔に言うと、 サブクラスを親クラス型の変数で取り扱っているからです。親クラス型の変数で扱う以上、親クラスのもつメンバしか使えません。
Blue0999

2016/04/04 08:48

playgroundでコードを少し変え試してみました。どう動いているのかはわかるのですが理論がわかりません。勉強し直してからもう一度教えていただいた事を読み返してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問