🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

Q&A

4回答

432閲覧

クラスを型指定に使用した場合について

aae_11

総合スコア178

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

0グッド

1クリップ

投稿2019/11/30 02:32

編集2019/11/30 02:32

以下のコードにつきまして、お聞きしたい部分があります。

class Car {} class Bike: Car {} class Track:Car {} let a: Car = Bike()

こちらなのですが、class Bike: Car {}はCarクラスを継承したBikeクラスであると思うのですが、let a: Car = Bike()こちらが何を意味しているのかが分かりません。インスタンス化した場合は対象のクラスのプロパティを使用できると認識しているのですが、let a: Carこのように型にクラスを指定した場合はどのような構造となるのでしょうか...?

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

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

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

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

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

guest

回答4

0

let a: Car = Bike()こちらが何を意味しているのかが分かりません。

何がわからないのかがわかりません。Car型として宣言した変数のaに、CarのサブクラスであるBikeのオブジェクトを入れているだけです。

投稿2019/11/30 02:45

maisumakun

総合スコア145967

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

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

aae_11

2019/11/30 02:52 編集

>Car型として宣言した変数のaに こちらなのですが、型にCarを指定した場合と、let a = Car()としてインスタンス化した場合の違いがよく分からなく、少し、混乱してしまったといった状況です。。
maisumakun

2019/11/30 02:54

「let a = Car()」は「let a : Car = Car()」の省略形です。右辺の型から左辺が型推論されています(Swiftの変数は静的型付けなので、書かなくても型は振られています)。
aae_11

2019/11/30 03:04 編集

>let a = Car()」は「let a : Car = Car()」の省略形です なるほどです... そうなりますと、インスタンス化する場合は、対象となるクラスを型の部分に指定しなければならないということでしょうか? いまいち型を指定する必要が分からなかったもので...
aae_11

2019/11/30 03:06

Carクラスの型を指定せずとも、let a = Car()とこのように記述するだけで、「Car()」はCarクラスだと断定できるような気がします...
maisumakun

2019/11/30 03:07

> Carクラスの型を指定せずとも、let a = Car()とこのように記述するだけで、「Car()」はCarクラスだと断定できるような気がします... だから「let a = Car()」と省略して書ける、という話なのですが。
maisumakun

2019/11/30 03:11

一方で、「let a: Car = Bike()」の場合、「: Car」を省くとaはBike型になってしまいます。
aae_11

2019/11/30 03:14

となりますと、「let a: Car = Bike()」こちら変数「a」はあくまで、Car型であるBikeインスタンスという扱いになると思うのですが、「let a: Bike = Bike()」とした場合では何か違いなどはあるのでしょうか?
aae_11

2019/11/30 03:21

バイクインスタンスを扱いたい場合、型にCarを指定せずとも「let a = Bike()」で良いのではないかと思った為、何かCarを型に指定することでBike型の指定では出来ないことがあるのかなと思ったんですよね。。
maisumakun

2019/11/30 03:24

「let a: Car」にはBike以外のCarも代入できます。
guest

0

Swiftは普段あまり触らないので、話半分くらいに見ていただきたいですが……

Dec 2, 2019 9:55pm追記: Macを触れる環境に来たので修正しました

swift

1 2// MARK: - 3class Car { 4 var name: String 5 var wheelsQty: Int 6 7 init(name: String) { 8 self.name = name 9 self.wheelsQty = 4 10 } 11 12 func run() { 13 print("Go ahead (self.name), zoom-zoom!") 14 } 15} 16 17// MARK: - 18class Bike: Car { 19 var hasSidecar: Bool 20 21 init(name: String, hasSidecar: Bool) { 22 self.hasSidecar = hasSidecar 23 super.init(name: name) 24 self.wheelsQty = 2 25 } 26} 27 28// MARK: - 29class Truck: Car { 30 var specialSigns: Array<String> 31 32 init(name: String, specialSigns: Array<String>) { 33 self.specialSigns = specialSigns 34 super.init(name: name) 35 } 36 37 override func run() { 38 print("Vrrr, Vrrrr, Vrrrrrrom!!!!") 39 } 40} 41 42// MARK: - 43class ViewController: UIViewController { 44 required init?(coder: NSCoder) { 45 super.init(coder: coder) 46 } 47 48 let touring = Bike(name: "Touring", hasSidecar: true) 49 let hayabusa: Car = Bike(name: "Hayabusa", hasSidecar: true) 50 let canter = Truck(name: "CANTER", specialSigns: ["危", "毒"]) 51 let elf: Car = Truck(name: "ELF", specialSigns: []) 52 53 override func viewDidLoad() { 54 print("(touring.hasSidecar)") // -> true 55 print("(hayabusa.hasSidecar)") // -> ERROR 56 57 print("(canter.specialSigns)") // -> ["危", "毒"] 58 print("(elf.specialSigns)") // -> ERROR 59 } 60}

投稿2019/12/02 07:55

編集2019/12/02 12:55
thyda.eiqau

総合スコア2982

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

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

aae_11

2019/12/02 12:02

ご回答ありがとうございます。 ご提示いただいたコードなのですが、自分の環境下でも試して見たいと思い、コピーアンドペーストでplaygroundに貼り付けさせて頂きましたら、何点かエラーが発生してしまいました... ご提示いただいたコードは、実際にxcodeなどで検証されましたでしょうか...?
aae_11

2019/12/03 00:14 編集

すみません。修正頂きありがとうございます。 ご回答頂きましたコード内で、分からない箇所がある為、お聞きしたいです。 「print("(hayabusa.hasSidecar)") // -> ERROR」こちらの部分なのですが、「Value of type 'Car' has no member 'hasSidecar'」エラーが出てしまいました。エラー内容から、「hasSidecar」がCarクラスに存在していない為のエラーかと思うのですが、「 let hayabusa: Car = Bike(name: "Hayabusa", hasSidecar: true)」こちらでインスタンス化していても、型に「Car」を指定していた場合、Bikeクラスのプロパティにはアクセス出来ないということでしょうか...? しかし、そうなりますと、型にCarを指定して、インスタンスを作成するメリットがないように感じてしまいます...自分の理解が至らないからだとは思うのですが、どうも混乱してしまいました...
ozwk

2019/12/03 00:12 編集

はい hayabusaはCar型で Car型にhasSidecarがないので コンパイラが「**Car**にそんなメンバーはない」と言っています
aae_11

2019/12/03 00:21 編集

>ozwkさん 返信ありがとうございます。 >コンパイラが「**Car**にそんなメンバーはない」と言っています こちらの点、やはりそうでしたか... しかし、そうなりますと余計、型にスーパークラスを指定し、インスタンス化するメリットってあるのかなと思ってしまいますね... 勿論使い道はあるのでしょうけど....
ozwk

2019/12/03 00:57 編集

「派生元の変数に派生したクラスのインスタンスが代入できますよ」の説明なだけであって 確かに参考書によくあるこの例でメリットは全然わからないと思います。 「代入」といっても本当に変数用意して代入して終わりだと確かに何のメリットもないんですが、 派生元で宣言されたものしか使わない関数を作る場合に、派生先を元として扱えれば 派生元を引数に取る関数を1つ作るだけで済むなどのメリットがあります doSomething_Bike(bike: Bike){} doSomething_Truck(truck: Truck){} が doSomething(car: Car){} の1つにできるということです 配列としてまとめたりもできるので sumWheelsQty(carList:[Car]){...}みたいなこともできるわけです
guest

0

Carクラスの変数にはBikeやTrackが代入できます。
ということですね

投稿2019/11/30 03:14

y_waiwai

総合スコア88038

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

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

0

追記

swift

1 2class Car { 3 let carStr = "carStr" 4} 5 6class Bike: Car { 7 let bikeStr = "bikeStr" 8} 9 10let a: Car = Bike() 11 12print("type(of: a): (type(of: a))") // => Bike 13 14// ↓これだと両方ともtrueになってしまう 15print("a is Car : ( a is Car )") // => true (`is` test is always true) 16print("a is Bike: ( a is Bike )") // => true 17// どちらの型で扱えばいいかわからない 18print("a.carStr: (a.carStr)") // => carStr 19print("a.bikeStr: (a.bikeStr)") // => compileError: Value of type `Car` has no member `bikeStr`

もともと

回答ではなく質問になってしまいますが。(コードあるのでこっちに書きます)

swift

1 2class Car {} 3class Bike: Car {} 4 5let a: Car = Bike() 6 7print("type Of a: (type(of: a))") // => type Of a: Bike 8 9

と、aBikeクラスとなってしまうので、クラス記述の実用性はなく?、代入できることを説明することを目的とした記述なのでしょうか?

投稿2019/11/30 03:27

編集2019/12/05 05:26
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

y_waiwai

2019/11/30 03:31

まあ、TrackもBikeも同じ型で操作できる、というのがミソでありまして、 統一的な処理ができる、のがいいのです
aae_11

2019/11/30 03:32

>クラスとなってしまうので、クラス記述の実用性はなく?、代入できることを説明することを目的とした記述なのでしょうか? いえ...実は「as」の意味について調べていましたら、質問に掲載させて頂いたコードが調べていた記事に掲載されていた為、引用させて頂いたといった形ですね...
aae_11

2019/11/30 03:34

>print("type Of a: (type(of: a))") // => type Of a: Bike こちらなのですが、「let a:Car」とCarを指定したとしても、型はBikeとなるのですね... どうも、ここの部分が混乱してしまっているといった状況なんですよね...
eytyet

2019/12/01 18:45

aはCar型です。Car型のメソッドやプロパティはa.xx()という感じで呼べますが、Bike型しか持っていないメソッドやプロパティをa.yy()と呼ぶ事はできません。Car型にできる事しかできません。実際にaが参照しているのがBike型なのに、できません。 つまり、aの宣言はBike型の実体を、Car型として扱います、という意味です。 しかし、実際にaが参照しているインスタンス(実体)は。Bike型です。Bike()として実体化しているので、当然Bike型です。そして、type(of:)はインスタンスの型を返す関数なので、Bike型を返します。また、 let b = a as? Bike とすることで、Car型ではなく、インスタンス本来のBike型として扱う事もできます。これがasの機能です。実行時に、実際の型に合わせた処理を選択できます。(なお、bはBike型ではなくて、Bike?型です。aがTrack型を参照していた場合は、bがnilになります。aはCar型なので、参照するインスタンスはCar型でもTrack型でもBike型でも、さらには将来Carを継承して作られる未知のクラスである場合さえあります。どのケースでも扱えるようにしなくてはなりません。as? Bikeとすると、Bikeじゃなかったらnilになります。未知のものはnilになるので、未知のものが来ても処理できます。) こんな回りくどい事ができる理由は、この仕組みによって拡張性をもたせられるからです。継承によって既存機能の再利用ができるうえ、Bikeのための新しい機能を追加する事もでき、さらに、今存在しない未知のものにさえ対応できます。スーパークラス"として"扱えるのは、このためです。
aae_11

2019/12/02 00:00

>eytyetさん ご説明頂きましてありがとうございます。 分からなかったのですが、ご説明頂きましたおかげで段々と理解が出来てきました。 すみません。理解の確認の為、ご確認頂きたい点があるのですが、aはCar型として扱える為、Carクラスのプロパティにアクセスできるが「let b = Bike()」このようにした場合、bはCarクラスのプロパティにはアクセス出来ず、Bikeクラスのプロパティにしかアクセスが出来ない、といった理解で合っていますでしょうか...?
eytyet

2019/12/02 06:46

"bはCarクラスのプロアティにはアクセス出来ず"、は語弊があるように感じますが、言いたい事は合っていると思います。 BikeはCarを「継承」しているので、Carと同じプロパティを持ちます。 bを使って、Bikeが持つCarと同じ部分にアクセスできます。 このBikeがもつCarと同じ部分を、Carのものとみるか、Bikeのものとみるかで言い方が変わると思いますが、共通部分をBikeクラスのもの、と考えたとき、bはBikeクラスのものにしかアクセスできない、と言う言い方ができますし、その理解で合っています。 ただ、言い方としては違和感があります。BikeのCarと共通の部分は、Bikeのものというより、Carのものと考える方がしっくりきます。なぜなら共通部分のインターフェースはCarで定義していて、Carのものだからです。実装はCarとBikeでは異なりますが、インターフェースはあくまでCarが決めていて、Bikeには手出しできません。 クラス定義、には、型(インターフェース)の定義と、実装の定義の二つの側面があり、それを区別する事で混乱を回避できてくるのかなと思います。 インターフェースのレベルでは、Carが全てを決めています。Bikeは、Carのインターフェースに影響を与えることはできません。Bikeのインターフェースとして独自のものを追加することはできますが、Carのインターフェースを変えられません。この意味で、CarのインターフェースはCarのものであって、Carを継承しているBikeは、Carのインターフェースをサポートしていて、Bikeのインターフェースに変えているのではなく、BikeのもつCarのインターフェース部分をBikeのインターフェースであるとは言いません。 実装は違います。Bikeの実装は、Carのものをそのまま使うこともできれば、Bikeの独自実装で置き換える事もできます。継承元のインターフェースは変えられませんが、実装は変えられます。Bikeの実装はBikeのものです。bがアクセスできる実装は、Bikeのものです。Bikeの実装がたまたまCarのものをそのまま使っていたらCarの実装が呼ばれますが、それを決めているのはBikeの実装であり、その意味でBikeの実装にしかアクセスできないと言う言い方は合っています。(なお、a: Car = Bike() としたaからアクセスできるのもBikeの実装です) aae_11さんは実装の事を主体に考えているので、BikeのもつCarから継承した部分はBikeのものと言いたいのではないかと想像します。機能を実装するプログラマとして、それは自然な考え方です。 型という抽象概念を基準にして、実装と型を分離し、一段高いレベルで検討できるようにしたのがOOPを始めとしたプログラミングパラダイムの優れたところであり、実装より型のほうにより注目します。そのため、Carで定義した型はCarのものという見方をします。本の説明なども、型(インターフェース)を主体にした言い方になっているのではないかと思います。そのつもりで読んでみると、よりしっくり来たりするのではないでしょうか。
aae_11

2019/12/02 07:40

ご丁寧に教えてくださりありがとうございます。 >実装より型のほうにより注目します。そのため、Carで定義した型はCarのものという見方をします。本の説明なども、型(インターフェース)を主体にした言い方になっているのではないかと思います。 こちらのように捉えて見ましたら、なんだか理解出来た気がいたします。 まだまだ、理解仕切れない部分はあるのですが、教えて頂いたことを念頭に、学習を続けていこうと思います。
退会済みユーザー

退会済みユーザー

2019/12/02 07:45

aがCarだとわからないと安全に扱えない気がするんですが、Carって判別する方法はありますか、 isでも===でもtypeOfでもBikeになったと思います。知ってたら教えて下さい。
退会済みユーザー

退会済みユーザー

2019/12/02 08:07

ありがとうございます
fuzzball

2019/12/04 06:27

print(a is Car) //=> true になりませんか? あと、isKind(of:)はNSObjectを継承していないと使えません。
thyda.eiqau

2019/12/04 06:56

> isKind(of:)はNSObjectを継承していないと使えません。 おっと、そうでした、失礼しました、、なかなかObjective-Cから離れられず、お恥ずかしい限りです
退会済みユーザー

退会済みユーザー

2019/12/05 05:28 編集

回答ありがとうございます。追記しました。 a is Car // => true a is Bike // => true となるので困ると思ったのですが、aをCar型として扱えと教えてくれる方法などありましたら教えて下さい。
fuzzball

2019/12/05 05:40 編集

どういうときに困ります?(あぁ失礼、回答に追記してましたね)
fuzzball

2019/12/05 05:58 編集

「どちらの型で扱えばいいかわからない」というのがおかしくて、どちらでも扱えるのでは? Bikeとして扱いたいのであればBikeにキャストすればいいかと。 (そしてやっぱり、どういうときに困るのかちょっと分からないです)
退会済みユーザー

退会済みユーザー

2019/12/05 06:16 編集

質問しといてなんなんですが、困る場面があるかな?と思っただけで、実際困っていないのでなんとも言えないんですが… ただ扱うべき型をコード上で取れる方法が用意されているかなと期待した次第です。 Q:何型で扱えばいいの? => A:Car型で扱ってね といった感じに簡単に取得できるのかなと。 あ〜、キャストせずに要素にアクセスしようとする考えが間違ってるのか。 is で true である扱いたい方に必ずキャストしてから要素にアクセスすると考えればいいのか。 扱うべき型を取得してから要素にアクセスするのと、扱いたい型にキャストしてから要素にアクセスするのは同じだとも思えるので質問自体がナンセンスかもしれません。 回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問