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

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

ただいまの
回答率

90.48%

  • Swift

    7505questions

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

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

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,121

Blue0999

score 60

ContainerViewController: UIViewController

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/03 17:21 編集

    ご回答ありがとうございます!
    僕がコードの意味を間違って理解してしまったのかもしれません。

    let parentController = self.parentViewController as! ViewController
    上記の例でself.parentViewControllerはそのクラスの親クラスを表すので上記はContainerViewControllerの親クラスだけUIViewControllerからViewControllerに変更してparentControllerに代入するのかと思っていたのですが…
    間違っている所を教えていただけると嬉しいです!

    キャンセル

  • 2016/04/03 17:32

    文法の改善

    キャンセル

  • 2016/04/03 18:12 編集

    > self.parentViewControllerはそのクラスの親クラスを表すので上記はContainerViewControllerの親クラスだけUIViewControllerからViewControllerに変更してparentControllerに代入する

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

    キャンセル

  • 2016/04/03 20:40 編集

    補足の説明では説明不足でした。すみません。
    改めて書きなおします。

             ContainerViewController: UIViewController
                       から
              ContainerViewController: ViewController
                     に変更しものを
                   変数parentControllerに代入

    親クラスは変更されたがContainerViewControllerを代入された事に変わりはない。なのになぜparentControllerからContainerViewControllerに宣言されたプロパティを参照できないのか?という事です。
     

    キャンセル

  • 2016/04/03 23: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でキャストして参照します。

    キャンセル

  • 2016/04/04 00:18

    もう一点勘違いしてそうな気がするところがわかったので指摘しておきます。
    「親クラスだけ変更する」という言葉です。
    今読み直すと、この言葉を
    「let parentController = self.parentViewController as! ViewController」
    の「as! ViewController」のことを意味したつもりで使っているように見えましたが、
    これは、親クラスを変更するという意味ではありません。
    指定のクラスにキャストするということです。
    キャストの意味がわかってなければ、swiftの入門書等をちゃんと読んで調べてください。

    最初の回答で指摘した通り、コンテナの親クラス/子クラスの話と、スーパークラス/サブクラスの継承の話は別の話ですし、
    ここで言っている「親クラスを変更する」というのが「スーパークラスを変更する」という意味で使っているのでしたら
    そもそもそんなことはできません。
    オブジェクト指向を理解している人が読んだら、そんなことはできるわけないという前提なので、話が通じないのだと思います。
    動物クラスのサブクラスである犬クラスに、今から植物クラスに属してねって言っているようなものですから、めちゃくちゃです。
    Odacchiさんも指摘されている通り、やはりオブジェクト指向の考え方ついて一度じっくり勉強する必要があるように思います。

    キャンセル

  • 2016/04/04 17:51

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

    キャンセル

0

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

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

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

Animal {
  func doSomething() // doSomething()メソッド
}

Human : Animal {
 var mind:Mind // mindプロパティ
  /*以下略*/
}

Dog : Animal {
  /*以下略*/
}

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/03 13:38

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

    キャンセル

  • 2016/04/03 21:46

    補足追記しました。

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

    キャンセル

  • 2016/04/04 17:48

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

    キャンセル

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

  • ただいまの回答率 90.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Swift

    7505questions

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