Objective-C Primer 番外編 7.オブジェクトを作る〜クラス〜

この回のタイトルは、「オブジェクト」から「クラス」に変わり、そして「オブジェクトを作る〜クラス〜」に変わりました。「オブジェクトの設計〜クラス〜」でも良かったのですが、「作る」という語感が易しそうなのでこれにしました。
 前回までに、int、char、ポインターというような単純なデータ型を説明し、構造体という複合的なデータ型を説明しました。単純なデータ型は言語の仕様として、あるいは処理系の仕様として最初から型の宣言がなされていましたので後はそのデータ型の変数を宣言して使用するだけでした。
 構造体の場合は、自分で型の宣言をして、そしてその次にその構造体の変数を宣言してはじめてその構造体が使えました。
 オブジェクトの場合も構造体と同じです。まずその型を宣言します。そしてその宣言したオブジェクト型の変数を宣言して実際に使い始めることになります。さらにオブジェクトが今までのデータ型と決定的に違う点は、そのオブジェクトがそのオブジェクト自身の動作・振る舞い、そしてそのオブジェクトの中のデータを操作するための仕組みも持っていることです。この動作・振る舞い・操作などをする部分をメソッドと呼んでいます。このメソッドは独特の記述方法で書かれていますが、中身は今までに出て来たC言語の関数と同じです。要するにオブジェクトは構造体にそのオブジェクト専用のメソッド(関数)がくっついたかたちになっています。したがってもうデータ型とは呼ばずにオブジェクトと呼ぶことになりました。

 多くのオブジェクト指向言語ではオブジェクトの定義(宣言)がされているものを「クラス」と呼び、そのクラスの変数を宣言して実際に使用できるようにしたものを「インスタンス」と呼んでいます。このことはObjective-Cでも同じです。そして「クラス」と「インスタンス」を合せて「オブジェクト」と呼んでいます。

なお、「宣言」と「定義」という言葉は、場合により使い方が変わってきます。だいたいの意味が通じればそれで良し、ということにしておきます。

では、サンプルコードからはじめます。サンプルコードは seito1m.zip からダウンロードすることもできます。



サンプルコードはダウンロードできますが、実際に打ち込まれることをおすすめします。
コメント(「//」で始まる部分や「/*」と「*/」で囲まれた部分)は打ち込まなくてもプログラムの動作には影響しません。今回のコードを自分で打ち込まれる場合にはコードファイルの拡張子が「.m」になっていることに注意してください。

seito1.m


d0122908_1245429.gif

いきなり汚いコードが登場してきましたが、先にすすみます。

実行画面
d0122908_1363061.gif


ターミナルでのコマンド説明
cd Desktop/vivacocoa
ターミナルを起動すると各ユーザーのホームフォルダにいることになっています。そこからデスクトップのvivacocoaフォルダに移動します。「cd」は移動を指示するコマンドです
cc seito1.m -framework Foundation
今までのCファイルのコンパイルと違うところは「-framework」オプションで「Foundation」フレームワークを読み込まなければならないことです。
./a.out
「./」(カレントディレクトリ)の「a.out」という実行ファイルの実行を命じています。

「点数 : 」と入力を促されたら色々な入力を試してみてください。
文字が入力された場合や、「+」や「-」付きの場合はどうなるのか
0〜100以外が入力された場合はどうなるのか。
などなど色々と試してみてください。
正しい数字が入力された場合は
「点数は○○点です」と表示してプログラムは終了します。
もう一度試してみたい時は「./a.out」とコマンドしてください。

ソースは少し汚いですが、ほぼ思い通りの動きになっていると思います。

この回の記事は「4.制御文その1」と「5.制御文その2」の前に書かれたものです。急遽、制御文の説明をしておく必要性を感じ「6.構造体」の前に説明を差し入れることにしました。この「7.クラス」の記事より4と5の制御文の記事のほうが新しく書かれたものです、もしかすると少し前に戻ったような違和感を感じるかもしれません。ご了承ください。



コード説明
今回のコードは一挙に長くなっていると思います。前回の構造体の宣言(定義)をしてその変数を宣言するという一連の流れだけでも、慣れないと「大変だな」と思われると思います。それがクラスの定義となるとさらに4倍ぐらいの手間がかかるように感じると思います。実際にその通りです。ただしCocoaでプログラムを作る場合、ほとんどはCocoaで用意されているクラスを使います。つまり小さなプログラムではここでのようなクラスの記述は1個か2個だけ自分で記述すれば良いのです。GUIを作るためのクラスも全部用意されています。あとはその用意されているクラスを使う方法を調べていけば良いわけですが、最低でも1つは自分でクラスを作ることになると思います。また用意されているクラスを使うためにもクラスの構造を知っておかなければなりません。
 今回のコード説明は相当に長文になります。なんとか読んで頂ければ幸いです。

d0122908_17162639.gif

1行目〜3行目。このファイルの中で使われているクラスや関数のヘッダファイル(定義ファイル)を#importで読み込んでいます。C言語では#includeで読み込んでいましたが、Objective-Cでは#importで読み込みます。この#importは何度記述しても同じヘッダファイルは読み込みません。「同じヘッダファイルを読み込む可能性ってあるの?」と思われるかもしれませんが、プログラムがもう少し長くなってくるとファイルを複数に分割したりします。その場合に2重読み込みをしてしまう可能性が出てきます。2重読み込みをすると同じ関数のプロトタイプなどが重複して設定されていることになりエラーとなります。

5行目。記号定数です。#define A B で、コンパイルの際にAの文字がBの文字に置き換わってコンパイルされます。

d0122908_1721233.gif

7行目から13行目。クラスの定義を行っています。クラスの定義は 、
  @interface で始まり @end で終ります。
クラス定義の1行目は、
  @interface クラス名 : スーパークラス名 とします。
@interface のあとのクラス名 (このサンプルコードでは Seito)は大文字で始めるのが慣習になっています。当然自分で作るクラスですから自分で名前を決めることができます。続けてコロン : を打ち、最後に スーパークラス名(このサンプルコードでは NSObject)を指定します。
 クラスはスーパークラスを必ず1つだけ指定しなければなりません。特別な理由のないかぎりNSObjectを指定します。NSObjectにはオブジェクトとして必要なデータ構造や動作・振る舞い(メソッド)が定義されています。それをスーパークラスとすることによってそれらの機能のすべてを継承することになります。つまり面倒な記述は自分でしなくて良いのです。
「あ、それは便利そう」と少しうれしくなりませんか?

 スーパークラスについては viva Cocoa ホームページの Objective-C Primer 「第1回 オブジェクト指向プログラミング」 を参考にしてください。

8行目から10行目。クラスの中で使う変数をブロック文 { } の中で宣言しています。この部分は構造体でのメンバ変数の宣言とまったく同じです。ただしObjective-Cのクラスではこの変数のことを インスタンス変数 と呼びます。またブロック文の最後 } にセミコロン ; が付かないことにも注意してください。構造体ではセミコロンが付きましたよね。
ブロック文のあとの11行目と12行目はC言語の関数プロトタイプの宣言と同じことをしているのですがC言語の関数とは記述の方法がかなり違います。そしてこのクラス内の関数のことを Objective-C では メソッド と呼んでいます。先頭に - の付いているメソッドのことを インスタンスメソッド+ が付いているメソッドをクラスメソッドと呼びます。ここでの説明はインスタンスメソッドのみになりますが、先頭の - と + にはそういう意味があることは覚えておいてください。そして関数プロトタイプと同じように最後にセミコロン ; が付きます。

 関数プロトタイプについては、 viva Cocoa ホームページの Objective-C Primer 「第4回 Objective-C言語への移行とリテラル定数」 の一番下の Column を参考にしてください。


 こうやって見ていくとObjective-Cの文法も今までCで勉強してきたことの応用で読んでいけることが分かります。なおメソッドの記述方法についてはのちほど説明します。

d0122908_17343269.gif

15行目から28行目。ここでインスタンスメソッド( - ではじまる) の実際の定義を行っています。
  @implementation クラス名 ではじまり
  @end で終ります。implementation とは 実装 という意味です。それぞれのメソッドの定義はC言語の関数定義とまったく同じことをしていると思ってください。違いは、
 1.返り値や引数の記述方法が違う
 2.メソッドはあるクラスのメンバのひとつとして書かれていることです。
 さて、アッサリと「返り値や引数の記述の方法が違う」と言いましたが、この記述方法に最初はかなりの戸惑いを感じることだと思います。


メソッドの記述方法
先頭にクラスメソッドであるかインスタンスメソッドであるかを表す + もしくは - を記述します。 
次にメソッドの返り値のデータ型を ( ) で囲んで指定します。何も返さない時には (void) と記述します。
そしてその次がメソッド名です。そして引数が続きますが、引数はサンプルのようにコロン : で区切っていきます。それぞれ引数の先頭にその引数のデータ型を ( ) の中に指定します。

 - (返り値のデータ型)メソッド名:(データ型)変数名:(データ型)変数名

 メソッド名 : の後ろからが引数です。引数はこのようにコロン : で区切っていくつでも増やしていくことができます。この記述方法ですと 
 - (データ型)名前:(データ型)名前:(データ型)名前
と、コロンで区切ってきれいに並ぶことになり、最初の名前がメソッド名で2番目以降は引数の変数名すなわち引数になります。

さらにもう1つメソッドの書き方があります。それは第2引数以降に対してラベルとして文字列を付ける方法です。そしてどちらかというとこちらの記述方法が主流と言えます。言葉の説明では分かりにくいと思いますので下記を見て下さい。

 - (返り値のデータ型)メソッド名:(データ型)変数名 ラベル名:(データ型)変数名

 ラベル名とその1つ前の引数の変数名との間にスペースが空いていることに注意してください。ここにスペースが空いていないと「変数名ラベル名」がひとつの引数ということになってしまいます。もう少し具体的な形で書けば、

- (BOOL)setTensuu:(int)val andName:(NSString*)name というメソッドがあれば、それを実際に使う時に、
setTensuu:95 andName:@"Yamada"
 という風に記述することになり2つの引数それぞれが何を表しているのか分かりやすくなります。
1. NSStringはCocoaの中に最初から用意されている文字列を表すためのクラスです。
2. ここで言っているスペースとは英語の半角スペースのことです。半角スペースなら1つであっても2つ以上であってもコード上の意味は同じになります。コード内の文字や文字列を表す場所以外で日本語の全角スペースを誤って使うとエラーとなる可能性があります。注意してください。


最後にCの関数と Objective-Cのメソッドを比較して書いてみます。この説明が1番分かりやすいかもしれません。
C関数の記述例
int goukei(int a, int b) {
    return a + b;
}

メソッドの記述例1
- (int)goukei:(int)a:(int)b {
    return a + b;
}

メソッドの記述例2
- (int)goukeiSuutiA:(int)a andSuutiB:(int)b {
    return a + b;
}

見て分かるようにブロック文の中は 3例とも同じです。
メソッドの記述例としては 記述例2のほうが一般的です。「こんなに長い名前」と思われるかもしれませんが、何の目的のメソッドで何の目的の引数なのかはっきりしていたほうが結局は分かりやすくて良いみたいです。

5/17/21:00
[PR]
by vivacocoa | 2007-05-06 12:04


<< テレビが見たい Objective-C Pri... >>