2009/12/09

Inheritance

3章のIndirectionの説明が終わったので、次に4章のInheritanceについて読み始めた。
Inheritanceとは日本語にすると「継承」 。

クラス同士で関係を持つときには2つの重要な要素があり、それがInheritanceとcomposition。Inheritanceという概念をマスターすることで、クラスを作った時にとその性質を他のクラスにも使うことができるという。
最初の文章ではクラス同士の関係のことをInheritance、その関係を実際に構築することをcompositionと言っているようだがどうなのだろうか。うっし、実際に読み進めて行くことにしよう。


Why use Inheritance ?

まず、そもそもどうしてInheritanceという概念が必要になってくるのかということで、前回使っていたサンプルからCircleクラスとRectangleクラスの宣言を例にして解説していた。





ここではクラス名以外は全く同じ宣言をしている。
そしてクラスの実行部でも宣言部と同様に、同じような命令を記述している。





このように何度も同じ記述をしていると、1箇所でも記述ミスをしたときにめんどくさい。そういった問題をなくすためには、各クラスの違う箇所だけを残して、共通の宣言は他でまとめて宣言すればいい。
つまり、このクラス宣言でいうdrawメソッドだけ残し、それ以外の宣言・実装をまとめてどこか違うクラスでまとめて行えばいいのだ。
その「Circleクラスはあそこのクラスを参考にして宣言・実装してくれ。」という命令のことをInheritanceという。代わりに仕事をさせるという意味では、これもIndirectionと言えるのか?

さっきから「どこかで」「あそこの」 という表現を使っていたが、Inhetitanceで参照されるクラスのことをスーパークラスという。CircleクラスとRectangleクラスの宣言を行うクラスをshapeとすると、「ShapeはCircleとRectangleのスーパークラスである」と言える。

そのスーパークラスShapeを宣言することで、CircleとRectangleを宣言するときは常にsetFillColor :とsetBounds:が引き継がれることになる。



Inheritance Syntax

では、このような機能を実装するために何が必要か見ていこう。
まずは受け手側となるCircleクラスの宣言を変更する必要がある。



Circleクラスの宣言についてはShapeクラスで宣言するので、ここではCircleクラスをShape型のクラスとしての宣言すれば問題ない。
そして、気になるShapeクラスの宣言だが、今までやってきた知識でまかなえるような記述だ 。


 

クラスそのものはNSObject型で宣言し、CircleクラスやRectangleクラスで共に使う2つのインスタンス変数、3つのインスタンスメソッドを宣言する。
宣言部と同様、実装部もとても簡単な方法で記述している。まずはCircleクラスの実装部。




drawメソッド以外は既にShapeクラスで実装されているので、ここで記述しない。
なぜNSLogだけ残したかというと、当然のことだがコンソールに表示させたい内容はクラスによって違うためである。
そして、Shapeクラスの実装は以下のようになっている。




これも今までの知識で十分にまかなえる記述だ。
あえてコメントするなら、後ほど使うdrawメソッドを空白でここでも記述していることについて。
drawメソッドは宣言こそ各クラスで共通して使うが、前述の通り実装方法はクラスによってそれぞれ異なる。なので本来ならばここで実装することは全く意味をなさない。しかし、Shapeクラスで宣言したからにはShapeクラスで実装しないとコンパイラが警告を出してしまう。そのため、とりあえず空白でも良いから警告を出させないためにとりあえず記述しちゃえということでこういった記述をしている。

さて。
次からは「How Inheritance Works」ということでInheritanceが具体的にどのような働きをしているか図を用いて解説している。
ざっと見てみると「self」 という単語も出ているのでさらにOBJCの理解が深まりそうだ。


※少し雑談
英文の読解についてはあらゆる人の助言を受けた結果、このような結果にたどり着いた。

Q.英語を読めません!どうやったら読めるようになりますか?


A1.ざっくり読む。翻訳するのではなく、その文章が何を言いたいのか理解する。

A2.英語は読める、読めないじゃない。読む、読まない。

ちょっと雑談になるが、去年スロベニアで出会った日本人の学生とチャットをする機会があった。
その中で英語を読むコツを聞いたところ、2個目のアドバイスを貰った。

英語では「I don't speak Japanese.」とは言うが、「I can't speak Japanese.」とは言わないそうな。
ラテン語などでも同じ言い回しをするらしい。だから「英語を喋れない」という表現をするのは日本くらい 。
というか、自分の英語レベルでもそれくらいはなんとなく覚えていた。

・・・確かに!!これも日本人の悪いところなのか。。。

それを少し意識するだけで本のペースは少し早まった。
重要そうでも分からない単語については辞書を引いているが、文章が何を訴えているのか分かるようになってきた。

先生がいない間に少なくともあと20ページ読んで、5章まではコンプリートしたい。

2009/12/01

昨日の疑問点について

クラスを定義する際のメソッドの宣言でcやbといったものを使っている理由。



ここでいうcやbはダミーと言って、実際にメソッドが実行される際には関係のないもの。
setfillColorを例にすると、このメソッドは実行されるとfillColorにShapeColor型の値を代入しろということをここでは述べている。具体的な値に関してはmain関数の方で準備されるので、ここではどのような値が入るかという例を示しているだけだ。なので、ここだけ見ると勝手にcを宣言して勝手にcを代入しているようにしか見えず、さらにこれらの命令が連続して行われるものとしてみてしまったために混乱が生じた。


ちなみに、CircleクラスのfillColorには以下の手順でkRedColorが割り当てられる。

main関数の中でCircleクラスのshapes[0]という構造体に対して、kRedColorという引数を用いてsetFillColorというメソッドを実行する。メソッドsetFillColorではfillColorに対してShapeColor型の値を代入しろと言っているので、与えられたkRedColorをfillColorに代入してやる。



そしてもう1つの疑問点。


main関数の最後でdrawShapes (shapes, 3)というメソッドを実行するように言っているが、そのカッコの中身の意味について。
実際にメソッドがどのように宣言されているかチェクすればすぐに分かった。

メソッドでは、id型のshapes[]とint型のcountに値を入れてから実行しろと言っている。
main関数で書かれていた(shapes, 3)というのはこれに割り当てるための引数だったのだ。
どのように使うかはこのメソッド内で定義している。
for文で3回分ループさせてiを1ずつ増やし、shapes[i]をid型のshapeに代入、そのshapeを使ってdrawメソッドを実行する。


このように、メソッド間のやりとりを読み取るのに苦戦した。
これがオブジェクト指向というものなのだろうか。自分でコードを全て記述するのは非常に困難だ。。。
iPhone SDKの恩恵の大きさを知った。

次回からは先生とマンツーマンで進めて行く。
よろしくお願いします。