第4章 クラス
クラスの作り方
オブジェクト指向言語と言えば、新たなクラスを作成する構文が何よりも重要と 言えましょう。Smalltalkでこれをするための方法を説明します。まずは、例か ら。
1 Object subclass: #TheSubclass
2 instanceVariableNames: 'instVar1 instVar2'
3 classVariableNames: 'classVar1 classVar2'
4 poolDictionaries: ''
5 category: 'TheCategory'.
6 !
ここでは、Objectクラス(Smalltalkの全てのクラスの基底クラス) の派生クラス TheSubclass を作っています。インスタンス変数 (C++で言う「データメンバ」)は instVar1 と instVar2、クラス変数(C++で言う「静的データメンバ」) は classVar1 と classVar2 です。また、Smalltalkの クラスはカテゴリ(category)に分類するのですが、ここでは、 TheCategory というカテゴリに TheSubclass を分類しています。
ここで何をやっているかと言うと、簡単な話、Object のクラスメソッドである、 subclass:instanceVariableNames:classVariableNames:poolDictionaries:category: (長い名前…)を実行しているのです。つまり、派生クラスを作 るのも、メソッドを実行するのです。
構文をまとめると、以下のような感じです。
1 基底クラス subclass: 派生クラス名のシンボル(つまり # を先行させる)
2 instanceVariableNames: インスタンス変数の並びの文字列
3 classVariableNames: クラス変数の並びの文字列
4 poolDictionaries: プールディクショナリの並びの文字列
5 category: カテゴリ名の文字列.
6 !
え? 「プールディクショナリ」とは何かって? ええと…よく知りません。(;) まあ、良いじゃないですか。ね。使ったこと無いですし…。だめですか?
よくある例ですが、猫を表すクラスでも作ってしまいましょう。インスタンス変 数は猫の名前です。
1 Object subclass: #Cat
2 instanceVariableNames: 'name'
3 classVariableNames: ''
4 poolDictionaries: ''
5 category: 'AnimalClasses'.
6 !
メソッドの作り方
メソッド(C++で言うところの「メンバ関数」)の作り方は少しト リッキーです。上で作った Catクラスのメンバ関数を作りましょう。まず、猫に 鳴いていただきましょう。引数をとらないメンバ関数 mew を作ります。
1 !Cat methodsFor: 'mewing'!
2 mew
3 Transcript showCR: 'mew'.
4 ! !
これがC++では、
// mewing
void Cat::mew()
{
cout << "mew" << end;
}
に相当すると言えばよいでしょうか? (厳密に言えば、void じゃないん ですよね。Smalltalkのメソッドはデフォルトでself~-(C++ 等のthisに相当)を返しますので)-~ 最初のチャンクで、 methodsFor: メソッドを実行して、つづくチャンクでメソッドの実装を 書きます。メソッドの定義の終わりは、空のチャンク(! ! の部分です)を書きます。(ちなみに、methodsFor: の引数には メソッドの説明を書きます) ともかく、これを書いた上 で、
1 |cat|
2 cat := Cat new.
3 cat mew.
4 !
とすると、ちゃんとTranscriptに mew と表示されるはずです。 (new クラスメソッドは自動的に定義されます)
つづいて、名前を設定したり、所得したりするメソッドを作りましょう。C++風 に書けば、
// accessing
void Cat::setName(string newName)
{
name = newName;
}
string Cat::getName()
{
return name;
}
にあたるようなメソッドです。Smalltalkでは、これらのメソッドは、setName のかわりに name: 、getName のかわりに name という名前をつける習慣になっ ています。
1 !Cat methodsFor: 'accessing'!
2 name: newName
3 name := newName.
4 !
5 name
6 ^name.
7 ! !
同じ説明(accessing)の元で複数のメソッドを定義するに は、! で区切ればよいだけです。また、^ がC++等 の return に相当します。新たに作った猫に tama という名前をつけて、それを表示するには、
1 |tama|
2 tama := Cat new.
3 tama name: 'tama'.
4 Transcript showCR: tama name.
5 !
とします。
ついでに演算子型のメソッドの作り方も紹介しましょう。今までと全く同じです。
1 !Cat methodsFor: 'bearing'!
2 + anotherCat
3 ^Cat new.
4 ! !
ええ、つまりですね、例えば、tama と nyanko という二匹の猫が子供を作りま して、chibi という猫を産んだとします。(笑) 以下のように書いて下さい。無 理矢理ですが。
1 |tama nyanko chibi|
2 tama := Cat new name: 'tama'.
3 nyanko := Cat new name: 'nyanko'.
4 chibi := tama + nyanko.
5 chibi name: 'chibi'.
6 !
name: のように、返値を明示的に返さないメソッドは、デフォルトでレシーバ自 身、つまり self (C++でいう this ) を返すので、
1 tama := Cat new name: 'tama'.
なんて書き方が出来るんですね。同様に子猫を産むところも、chibi := tama + nyanko name: 'chibi'. なん て出来ます。
クラスメソッド
クラスメソッド(C++でいうところの「静的メンバ関数」)を作り ましょう。今までは、new: で作った猫は最初は名前がついていなかったので、 新たな猫を作ると同時に名前をつけるようにしましょう。
1 !Cat class methodsFor: 'creating'!
2 new!WithName: newName
3 |newCat|
4 newCat := self new.
5 newCat name: newName.
6 ^newCat.
7 ! !
methodsFor: メソッドの前に、class メソッドで、クラスメソッドを作ることを 明記すれば良いんですね。(そう、Smalltalk では、new もクラスメソッドでし かないということを思い出しましょう) self は何度も言ってきたように、C++等の this に相当します。ではこ の場合の self は一体どのオブジェクトでしょうか? この newWithName: クラス メソッドに Transcript showCR: self. とでも書けば分かります が、self にはオブジェクト Cat が束縛されています。C++等では考えられない ことですが、全てのクラスもオブジェクトである、純粋なオブジェクト 指向言語であるSmalltalkでは、このように変数にクラスが束縛されていること もあるのです。
使い方は以下のとおり。
1 |tama|
2 tama := Cat newWithName: 'tama'.
3 Transcript showCR: tama name.
4 !
- 結局のところ、Smalltalkのソースコードがどのように見えるか示しましょう。
1 "animal.st"
2 Object subclass: #Animal
3 instanceVariableNames: 'name'
4 classVariableNames: ''
5 poolDictionaries: ''
6 category: 'Animals'.
7 !
8 !Animal class methodsFor: 'creating'!
9 new!WithName: newName
10 |newAnimal|
11 newAnimal := self new name: newName.
12 ^newAnimal.
13 ! !
14
15 !Animal methodsFor: 'accessing'!
16 name
17 ^name.
18 !
19 name: newName
20 name := newName.
21 ! !
22
23 Animal subclass: #Cat
24 instanceVariableNames: ''
25 classVariableNames: ''
26 poolDictionaries: ''
27 category: 'Animals'.
28 !
29 !Cat methodsFor: 'mewing'!
30 mew
31 Transcript showCR: name, ': mew!!'.
32 ! !
33
34 Animal subclass: #Dog
35 instanceVariableNames: ''
36 classVariableNames: ''
37 poolDictionaries: ''
38 category: 'Animals'.
39 !
40 !Dog methodsFor: 'barking'!
41 bark
42 Transcript showCR: name, ': bowwow!!'.
43 ! !
44
45 "main routine"
46 |aCat aDog|
47 aCat := Cat newWithName: 'tama'.
48 aDog := Dog newWithName: 'kuro'.
49 aCat mew.
50 aDog bark.
51 !
そうそう、言い忘れていましたが、Smalltalkの全てのメソッドは原則、C++でい う public 、インスタンス変数は原則 protected です。
