オプジェクト - みる会図書館


検索対象: 月刊 C MAGAZINE 2001年6月号
57件見つかりました。

1. 月刊 C MAGAZINE 2001年6月号

Fig. 3 提供されるマクロ Data_Wrap_Struct(VALUE klass , void ( * mark) ( ) , void( * free) ( ) , void * sval) ポインタをラップしたオブジェクトを生成して返す。 k ss は生成されるオブジェクトのクラス , ma 「 k は GC のマークフェイズで呼ばれる関数へのポインタ , f 「 ee は GC で回収されたときに呼ばれ る関数へのポインタ , sval(i ラップされるポインタとなる Data_Make—Struct (klass , type, mark, free , sval) type 型のデータをヒープに割り当て , sva に代入し sv 引をラップしたオブジェクトを生成して返 す。 type 以外の引数は Data—W 「 ap—Struct と同じ Data_Get_Struct(obj , type, sval) obj から type 型のデータへのポインタを取り出し , sva に代入する オプジェクトでラップしたり , ラップした オプジェクトからポインタを取り出すため には , Fig. 3 のようなマクロを利用します。 国 card 拡張ライブラリ では , wildcard 拡張ライプラリのソース コードを見ることにしましよう ( ⅵ ldcard. c , 付録 CD - ROM に収録 ) 。ライプラリ名が変 わっただけですが , 一応 extconf. rb ( 付録 C D - ROM に収録 ) に示しておきます。 wildcard s new ( ) wildcard—s—new ( ) は W11dCard オプジェク トを生成します。引数の処理などは朝 match ライプラリの fnmatch_fnmatch ( ) とほとん ど同じです。 WildCard オプジェクトは patte rn, flags という 2 つのメンバを持つ wildcar d 構造体へのポインタをラップします。 Dat a-Make-Struct ( ) の第 1 引数には self を指定 していますが , self は WildCard クラスを指 します (WildCard クラスのサプクラスを作 成した場合は , サプクラスになります ) 。第 4 引数には wildcard free ( ) という関数を指 定していますが , wildcard_free ( ) は patt ern と構造体そのものを仕 ee ( ) します。 pat tern 用のメモリ領域を割り当てるために用 , LOC-N(type, n ) というマクロを利用して いますが , これは ruby. h で提供されるマク ロで , 必要なら GC を起動してから , sizeof (type)xn ノヾイトの領域を ma Ⅱ。 c ( ) します。 wildcard-pattern() , wildcard flags() から wildcard 構造体へのポインタを取 り出し , それぞれ pa rn と flags の値を返し ます。 wildcard-pattern ( ) では rb-str-new2 ( ) という関数を使用していますが , これは引 数で指定した内容の String オプジェクトを 生成する関数です。 wildcard match ( ) wildcard match ( ) は self から wildcard 構 造体へのポインタを取り出し , pattern と fla gs の値を使ってマッチング処理をします。 処理は fnmatch-fnmatch() とほば同じです。 lnit—wildcard() WiIdCard というクラスを作成し , メソッ ドや定数を定義しています。 rb_define_sin gleton-method ( ) は特異メソッドを定義す る関数です。この場合はクラスの特異メソ ッド , すなわちクラスメソッドを定義して います。また rb define_method ( ) はイン スタンスメソッドを定義します。 WIIdCard#match の別名として WIIdCard# = を用意していますが , これは case や Enu merable#grep などで W11dCard オプジェクト を利用できるようにするためです ( Iist10 ) 。 今回はモジュールで関数的なインタフェ イスを提供する方法と , クラスを定義する , よりオプジェクト指向的な方法を説明しま した。必ずしも , 後者のほうが優れている とは限らないので , ケースパイケースでよ りよい方法を選択してください。ただ , C のライプラリで , ある構造体を操作する関 数群が提供されているような場合には , そ の構造体をラップするクラスを定義するほ うが自然だと思います。 さて , 2 回にわたって拡張ライプラリの 作成について説明してきましたが , いかが でしたでしようか。説明が不十分な部分も 多いと思いますが , 足りない情報は Ruby の アーカイプに含まれる README. EXT. jp な どで補ってください。また , 拡張ライプラ リの作成に関する話題を扱う ruby - ext とい うメーリングリスト [ 参考文献 3 ] もあります。 次回は C アプリケーションへの Ruby イン タブリタの組み込みについて説明します。 [ 参考文献 ] [ 1 ] 「 XMLParser モジュール」 , 吉田正人氏 , http://www.yoshidam.net/Ruby-ja.hⅲ11 #xmlparser [ 2 ] "expat - XML parser Toolkit" , James CI ark , http: 〃 www.jclark.com/xml/expat. html [ 3 ] ruby-ext ML, ruby-list-ctl@ruby-lang.org , URL:http://www.ruby-lang.org/ja/ml.html case や grep での利用 HEADER—PATTERN = WiIdCard. new("*. h") SOURCE—PATTERN = WildCard. new("*. c") case filename when HEADER—PATTERN when SOURCE—PATTERN List ・ sources = filenames. grep(SOURCE—PATTERN) Ruby マスターへの道 9 /

2. 月刊 C MAGAZINE 2001年6月号

どの alloc , init は Foundation フレームワー クの場合 , NSObject. h というへッダファイ ル内で , @interface NSObject ... ( 略 ) . (id)init; ロ 十 ( 土 d ) a Ⅱ 0 @end と記述されています。つまり , [ [MyObject a Ⅱ oc] 土 n 土セ theOb j と記述した場合 , a110C というクラスメソッ ドで MyObject オプジェクト ( インスタンス ) を発生させ , 発生したオプジェクトに init というインスタンスメソッドを使って , 初 期化を行っているわけです。 ところで , 先ほどから「 id 」というキーワ ードが出ていますが , これは Objective-C で は「汎用的なオプジェクトボインタ」型とい う扱いをする型です。 人によっては id というのは void ポインタ や Variant 型に似ていると感じるかもしれ ませんが , id はあくまでオプジェクトしか ポイントしないので , ポイントしている先 に数値データや非オプジェクト型データは 存在しません。 C + + と違って Objec ⅱ ve - C にはテンプレー トという概念はなく , C + + ほど強く型に縛 られているわけでもありません。 C + + では 可変長配列を作るときに STL の vector を利 用しますが , このときどの型の vector であ るかを明示しなくてはなりません。同じこ とを Objective-C で行う場合 , どの型の可変 配列かを明示しなくても , id 型の可変配列 で作成すればいいのです。 Foundation フレームワークでは , NSMu tableArray という可変配列が用意されてい ます。たとえば List 4 のようなプログラム があったとすると , theAr ・ ray に対して Bird Class オプジェクトと DogClass オプジェク トが格納され , それぞれのオプジェクトに 対して Naku メッセージが送られます。す ると , それぞれのオプジェクト固有の Nak u メソッドが適切に呼び出されるのです。 C + + の場合は仮想関数を使わなかった場 合 , 適切なメンバ関数が呼ばれない不都合 が起こることがありますが , Objective-C で はそもそも仮想関数という考え自体がなぐ注 3 ] 指定されたメッセージに応じた適切なメソ ッドが確実に呼び出されます。それどころ か , List 4 で , [theObjPtr Naku]; と記述した部分を , [ theOb j ptr Tobu]; に変更してもコンパイルできるほどです。 ただし , これはコンパイルはできたとし ても実行時に DogClass オプジェクトに対 して Tobu メッセージを送るため , Tobu メ ソッドを持っていない DogClass オプジェク トはどのように行動してよいかわかりませ ん。結局 , 実行時ェラーとなり , 例外が投 げられたりプログラムが停止する可能性が あります。 セレクタ (selector) オプジェクトに対して送られるメッセー ジは実行効率を考えて , 文字列ではなくも っと効率のいい情報にコンパイルされます。 この情報は , 変数に格納したり利用するこ とが可能で , セレクタと呼ばれています。 セレクタを , C + + でいうところのメンノヾ 関数ポインタだと勘違いする人がいるかも しれません。しかし , メンバ関数ポインタ IS NSMutab 厄 A 「「 ay による汎用オブジェクト配列 @interface DogC lass NSObject (void)Naku; @end @interface BirdC lass - ( vo 土 d ) で。 b ヂ (void)Naku; @end : NSObject 144 C MAGAZINE 2 1 6 [ theBird re lease [ theDog て引 ease [theArray release]; ItheObjPtr Naku]; id theObjPtr = [theArray 0bjectAtIndex: theIJ; for(thel 咢の thel く [theArray count]; thel 十十 ){ ttheArray addObiect:theDog]; [theArray addObject:theBird]; BirdClass *theBi て d ま [[BirdCIass alloc] 土 n 土し DogCIass *theDog = l[DogClass a 日 0C1 init]; NSMutableArray *theArray = [ [NSMutabIeArray aIIOCJ 土 ni セ 土 n し thel; s し c void Test(void) SEL 型を取り扱う [theBird releasel; [ theBird performSe 厄 c し or : theSeI ector SEL theSelector = @selector(Tobu) デ BirdClass * theBird = [ tBirdClass alloc] init]; @p 「 0t0C6 @end (id)Clone; ② p て OtOC 引 C neP て 0 セ OC 引 @end - ( メソッドの型 ) インスタンスメソッド名 : ( 引数の型 ) 引数 . @p 「 OtOC プロトコル名 Fig. 3 プロトコルの宣言

3. 月刊 C MAGAZINE 2001年6月号

スタートアップ Ja a Java 言語事始 コ、ラ UML ちょっとだけ入門 ( 2 ) ークラス図 されました。 ではこれを使おうとして , array[0] とか代入しようとするとエラーになります。 「あっ。しまった。配列のサイズを書き込 むのを忘れた。 int[ 引 a 仼 ay ; と直そう」と考 えそうですが , 直しても受け付けてくれな いはずです。 Java においては , 配列もオプジェクトで あり , 「型」としては , クラスと同じ参照型 なのです。使う前にはまず new によって生 成しなければなりません。具体的には , た とえば要素 5 個の配列がほしいときは以下 のようにします。 array = new int [ 5 宣言と同時に初期化することもできま int [ ] array = new 土 n 日 5 ] ・ 少々わかりにくいと思いますが , さっき のクラス型の宣言と比べてみてください。 Data d = new Data ( 基本的に同じだということがわかります。 int[l と Data が型名。 d と array が変数名。ま あ右辺の形式がちょっと違うけれど , new でオプジェクトを作り出しているところは 同じです。この場合 , イメージとしては Fig. 3 のようになっています。 では次に参照型の配列を見てみます。 言のしかたはだいたい同じ。また , 初期化 もできます。 Data[ ] dataArray = new Data [ 5 嵭 言をした。初期化をした。ではこれを 使おうと思って , dataArray[1]. value = 3 ; な んてやると , またもやエラーになります。 オプジェクトが作られていないのです。「今 newData [ 5 ] って作ったじゃないですか・ ・・・」 , 「それは「配列』のオプジェクト 0Data 型 1 個 1 個のオプジェクトはまた別なので プリミテイプ型の配列の要素と参照型の 配列の要素とでは , ちょうど Fig. 1 に示し たような違いがあります。参照型の要素は オプジェクトへの参照を保持するだけなの で , オプジェクト自体は別に作らなければ す。 クラス図は , プログラム中で使われるク ラスとクラス間の関連などからなる図で , プログラムの静的構造を表すものです。 U ML の中でも中心的な位置を占めています。 クラスは , 四角の箱で表します ( Fig. A ) 。 Fig. A ー ( a ) のように単に四角の中にクラス 名を入れただけでもいいのですが , 属性 ( J ava ではフィールド ) を書き入れたいときに は籍を区切って 2 段目に書き入れ ( Fig. A ー (b)), 操作 ( Java ではメソッド ) を書き入れ たいときには 3 段目に書き入れます ( Fig. A ー (c) ) 。また , 責務を , つまり「何をするクラ スか」を記入したいときには , 'ResponsibiI ities" と記して 4 段目に書き入れることがで きます (Fig. A-(d)) 。 2 つのクラスの間に「関連」がある場合 , 実線で表します ( Fig. B-(a))0 これは少な Fig. A クラス図の基本構成 ( クラスの表記 ) (b) (a ) Point Physique int x lnt y クラス同士の関係を示す場合の表記 くとも片方が相手への参照 ( 前号参照 ) を保 持していることを意味します。関連はあく まで静的な関係を表します。たとえば Gr 叩 h ics クラスがメソッドの引数として Color ク ラスを受け取ることがありますが , これは 関連とはいいません。こういう関係は「依存」 といい , 破線の矢印で表します ( 日 g. B-(b))0 クラス間の関係だけではなく , より詳し くオプジェクト間の関係を表したいときが あります。オプジェクト ( インスタンスと もいう ) を表すには , クラス記法の名前に あたるところに下線を引きます (Fig. C- (a) ) 。何のクラスに属するオプジェクトか を表したい場合 , コロンで区切ってクラス 名を書きます ( Fig. C ー ( b ) ) 。名前を明示す る必要がない場合 , Fig. C ー ( c ) のように表 すことができます。 (c) Ca 「 go() stop() (d) Timer Responsibilities 一定時間の 経過を告知する Fig. C オブジェクトの表記 (a) Human Graphics Monster Colo 「 te 「 ao (a) (b) kaiou:Human (c) ・ Human なりません。上のように初期化したうんて dataArray[ 0 ] dataArray[ 1 ] dataArray [ 4 ] new Data ( new Data ( new Data( というように , それぞれの配列要素にオプ ジェクトを代入します。イメージとしては Fig. 4 のようになっています。 筆者は以前 , C 言語の配列を「不動産」に たとえたことがあります。一度作ったら動 スタートアップ Java 71

4. 月刊 C MAGAZINE 2001年6月号

本的には C 言語と同じです。ただしオプジ ェクトを利用する場合 , " [ " と " ] " で囲んだ 部分に「メッセージ式」を記述します。メッ セージ式の基本的なフォーマットは , [ レシーバセレクタ : 引数… ] となっています。 レシーノヾ ( receiver ) というのはメッセー ジを受け取るオプジェクトのことです。メ ッセージを受け取ったオプジェクト ( つま りレシーバ ) は受け取ったメッセージに応 じたメソッドを起動し , その結果 ( 戻り値 ) がメッセージ式の値となります。 ただし , C 言語と同様 , void 型メソッド の場合 , メッセージ式の値はありません。 先ほどの MyObject オプジェクトで applicat ionShouIdTerminate メソッドを使う例でい えば , List 3 のようなプログラムが記述さ れていた場合 , [theObj applicationShould Terminate:theApp] は , 常に YES の戻り値 tNSApp setDelegate:selfl; [myWindow makeKeyAndOrderFront:seIfl; (void)awakeFromNib Test( NSBeep ( NSLog()" * Action * ″ (void)myAction: (id)sender @implementation MyObject 博 @implementation @end (BOOL)applicationShouIdTerminate: (NSApplication - (void)awakeFromNib; (void)myAction: (id)sender; id myWindow; @interface MyObject : NSObject 、 @interface となるため , 常に EndProc ( ) が実行されま づ - [ 注 1 ] また , メッセージ式は入れ子を認めてい ます。 List 3 で , MyObject * theObj [ [MyObject alloc] 土 n 辻 となっている部分は , MyObject * theObj; [MyObject alloc]; / / 確保 theOb j = [theObj 土 ni セ / / 初期化 theObj = の 3 行を凝縮したものです。 (class method) クラスメソッド でいうところの new , delete に相当するも C + + とは比較にならないほど少なく , C + + Objective-C は , 予約語や言語拡張部分が ライプラリの支援が重要です。というのも Objective-C でプログラミングを行うには , 真紀俊男の ローテク講座 のもライプラリで実現しているのです。 Project Builder で利用する Foundation フ レームワークの場合 , a Ⅱ oc でオプジェクト の確保を行い , init で初期化をし , release で解放することになっています [ 注 2 ] 。この とき問題になるのは , 最初のインスタンス を発生させる時点ではインスタンスメソッ ドが使えないことです ( まだインスタンス が発生していないため ) 。そのため , クラ スそのものをオプジェクトとみなして ( ク ラスオプジェクトとみなして ) , そのオプ ジェクトに対して a Ⅱ oc メッセージを送り , インスタンスを発生することになります。 このときに利用されるメソッドをクラスメ ソッド ( あるいはファクトリメソッド ) と呼 びます。 クラスメソッドは , インスタンスメソッ ドと区別する意味でメソッド名の前に「 - 」 ではなく「 + 」を付けます。ちなみに , 先ほ * )sender; (BOOL)applicationShouIdTerminate: (NSAppIication * )sender NSLog (@"app IicationShoul dTerminaten return YES ー @end メッセージ式の評価 インスタンス変数の宣 @interface クラス名 : 継承元の親クラス名 Fig. 1 Objective-C での「クラスの宣言」 EndProc ( if( [theObj applicationShouldTerminate:theApp] ) { //theObj に applicationShouldTerminate メッセージを送る MyObject *theObj = [ [MyObject allocJ 土 n 土し 〃オブジェクトの確保と初期化をする NSApp *theApp = NSApp; - ( メソッドの型 ) インスタンスメソッド名 : ( 引数の型 ) 引数 . @implementation クラス名 Fig. 2 メソッドの実装 @end - ( メソッドの型 ) インスタンスメソッド名 : ( 引数の型 ) 引数 .. 真紀俊男のローテク講座 @end メソッドの実装 143

5. 月刊 C MAGAZINE 2001年6月号

参照型の変数は , ( ローカル変数を除い ては ) デフォルトの値は null という特殊な 値です。これは「何も指していない」ことを 意味します。また , 参照型変数には nu Ⅱを 代入することができます (x = null; というよ うに ) 。これは「そのオプジェクトはもう いらない」ということであり , 変数からオ プジェクトへの参照を断ち切ります。どの 変数からも参照されなくなったオプジェク トは自動的に消去されますにの機構をカ べージコレクションといいます ) 。 ー String 型 こでちょっと String 型について説明し ておかなければなりません。この String と いうのは , 標準ライプラリの java. lang パッ ケージで定義されている string クラスで す。クラス型だから当然参照型です。ただ これは , ほかの参照型と大きく異なってい ます。 1 つは String 型のリテラルが存在するこ とです。前述のように "abcdefg" のように 二重引用符で囲んだ文が String 型のリテラ ルになります。これは , string s = nabcdef" のように変数に代人することができます。 もう 1 つ , 参照型の中で String 型だけは + 演算子が使えるのです。 String 型の変数で もリテラルでも , + で結び付けるとそれが 合わさった String 型が生成されます。たと えば "abc" + "def" で "abcdef" という文字列 が生成されます。 さらに , string 型とほかの型が + で結ば れている場合 , 「ほかの型のほうを文字列 にして string 型と合成する」という働きが あります。たとえば List 7 の 3 行目のように すると「 x の値は 5 です」と表示されます。 文字列はプログラム中できわめて多く使 われるので , 特別扱いしているわけです。 この機能がないと , たとえば同じ表示をし ようと思っても , List 7 の 5 行目のようにな ってしまいます。 ・・・まあ , できることは できるんですけど , やつばり 3 行目のほう / 0 c MAGMINE 2()() 1 6 List 7 Fig. 5 Fig. 4 Fig. 3 St 「 ing の連結 土 n セ x = System. out.println()x の値は”十 x 十″です” 5 : System. out.println( ( ( "x の値はつ . concat( lnteger ・ tostring(x) ) ) . concat( ”ですっ 4 : 3 : 2 : 1 : プリミテイプ型の配列 ar 「 ay 参照型の配列要素 dataArray Java の配列のイメー 配列型の変数 [ 0 ] 4 [ 0 ] オブジェクト [ 2 ] 0 [ 2 ] 1 [ 3 ] [ 3 ] 6 [ 4 ] [ 4 ] 8 オブジェクト シ が楽ですね。 配列型 配列オブジェクト 配列の要素のオブジェクト オブジェクトオブジェクト まずプリミテイプ型の配列から。たとえ しれません。注意して読んでください。 ず表記は似ているので , 混乱しやすいかも 「型」の最後に配列についてお話しま す。 最初に言ったとおり Java の文法は C / C + + と似ているのですが , 「配列」に関しては根 本的に違います。違っているにもかかわら ば int 型の配列ならこう宣言します。 int [ ] array; int array[ 嵭 れによって array という int 型の配列が宣言 の方法で宣言してください。とりあえずこ 2 種類あるのが変ですが , 基本的には ( a )

6. 月刊 C MAGAZINE 2001年6月号

特集 2 Mac 05X アコリケーション開発ガイド ( コラム 5 を参照 ) のコントロールに相当す に対してメッセージを送り , コントロール ルにします。 るオプジェクトを作成して , ボタンやメニ オプジェクトがビューに対して赤い丸 ( あ MyView クラスを作成したのと同じ要領 ューが選択されたときにこのオプジェクト るいは赤い四角 ) を描くよう要求するモデ で , 今度は NSObject クラスを継承する「 My Fig. 13 MyCont 「 0 Ⅱ e 「のインスタンス化 Fig. 14 アイコン化された MyCont 「 0 Ⅱ e 「 t ・汁 a ( ・名… 日厄 Edit Cla に 5 FO 「 m 誂 Layout M 引 nM n リ諏物 ー ns ねれ 0a55e5 lmages Sounds Subclass Main lnstantiate lnstances 、 ( asse Edit ロぉ 5 Add Outlet Add Action Read Fi &.. Create Files... 扣 v 工は ng. 0 切にロ N50 切ロ Fi rstRes ponder マ 旧ⅲ spe ( tO 「 旧 P に NSA 「「こ y NSMutabIeArray NS 〔にⅱ NSActionCell NS & u び orl 〔をⅱ 日に Owner 「 i 「 R に 500nd 曾 MainMenu My ( 0 れ t 「 oll び マ ー宀・ 1 1 MyCO れび引厄「 MyWindow マ ※ MyCont 「 0 Ⅱ e 「を選んでから lnstantiate を選ぶ コラム 5 MVC (ModeIView Contr011er) MVC とは , 一般に GUI アプリケーション ンスや再利用を有利にしようという考えで ころの Mediator 的なオブジェクトとして説 を組み立てるとき , 外観 (View), モデル ( M す (Fig. B)O 明しています (Fig. C) 。いずれを示してい odel) , 入力 (Controller) の 3 つに分離して組 ところが , Currency Converter T 猷 or 回 るにせよ , G 団アプリケーションの設計と み立てることでプログラムが一枚岩構造に など Mac OS X 関連のドキュメントで紹介 施工をするうえで重要な考えであることに なって肥大化することを防止し , なおかっ , されている MVC では Cont 「 0 「は Model と Vi 違いはありません。 分離したそれぞれのモジュールのメンテナ ew を仲介する , デザインパターンでいうと Fig. B 一般的な ModelView Controller(MVC) Fig. C Mac OS X での ModelView Cont 「 olle 「 (Currency converte 「 Tuto 「 ia はり引用 ) Model \./iew View Controlle 「 Model Cont 「 0ⅱe「 イ 9 特集 2 MacOSX アプリケーション開発ガイド

7. 月刊 C MAGAZINE 2001年6月号

真紀俊男の ローテク講座 super init] が追加されるのですが , おもしろいこと その実態が謎につつまれていることの多 というのも , やはり自分自身の呼び出し に BeastClass を継承したクラス , つまりこ い Object ⅳ e - C の理解につながれば幸いで なのですが , こちらは親クラスにある init こでは CatCIass にも walk メソッドが追加さ す。 メソッドを呼び出します。もし , こで れたのと同じ結果になります。実際に List [ 注 ] うつかり , 11 のようなプログラムを実行させると追 self init] [ 1 ] 常に YES の戻り値となるため 加された walk メソッドをそのまま実行して とすると , そのまま再帰呼び出しになっ BOOL は Objective-C で論理型として利用 しまいます。これは C + + の継承では考えら てハマり込んでしまいます。 されるキーワードであり , YES ( 真 ) または れない技であることはいうまでもありま NO ( 偽 ) のいずれかの値しかとらないこと せん。 カテゴリ (category) になっています。 bjective-C の参考文献 [ 2 ] 回 ease で解放することになっています Objective-C の柔軟性を特徴づけるクラス 実際の解放は dea Ⅱ oc メソッドで行いま 拡張機能の 1 っとしてカテゴリがあります。 残念なことに , Objective-C に関する本は , すが , 参照カウンタによるメモリ管理を カテゴリも継承と同様にクラスを拡張す あまり見つけられません。特集記事で紹 行うため , release メソッドを使います。 al る仕掛けです。継承と違う点は , すでに 介した Apple が公開している「 ObjC. pdf 」は 10C でオプジェクトを確保した時点で参照 存在するクラスにメソッドを追加できる 194 ページ程度の英文ですが , 現時点では カウンタは 1 にセットされ , 複数のポイン ということです ( ただし , インスタンス変 確実に見つけられる文献でしよう。また タから指示されるたびに参照カウンタを 1 数の追加はできません ) 。 Objective-C の原作者が執筆した , ずっ増やします。ポインタの指示を減ら 『オブジェクト指向のプログラミング たとえば , BeastClass を継承して List 9 すときは , release メソッドを使うことで のような CatClass ができているとしましよ 改訂第 2 版』 , B. J. Cox/A. J. Novobilski, 参照カウンタを 1 ずつ減らし , その時点で つこでは CatClass オプジェクトの cry 参照カウンタが 0 だったら release メソッド トッパン旧 BN4-8101-8046-8 メソッドを呼び出しています。 こでカ にも仕様は記述されていますが , この本 は dealloc メソッドを呼び出してオプジェ テゴリを使って BeastClass に walk メソッド 自体が現在 , ほとんど流通していない状 クトを解放します。 を追加しましよう。 [ 3 ] 仮想関数という考え自体がなく 況です。 既存の「@interface BeastClass 」と「@impl 以上 , ざっと , かけ足で Objective-C の概 本来のオプジェクト指向では仮想関数 ementation BeastClass 」の記述はそのまま 要を説明しました。誌面の都合上 , あま という考えはなく , 実行効率を重視する にしてⅡ・ t10 のような一ドを追加します : り詳細な説明ができないのが申し訳ない ために確信犯的に仮想関数を導入した C + + これによって , BeastClass に walk メソット ところですが , 名前をよく聞くわりには , 独自の考えでしよう。 カテゴリで BeastCIass を拡張する オリジナルの CatClass @interface BeastCIass (WalkCategory) ー (void)walk; @end @implementation BeastCIass (WaIkCategory) (void)walk @interface BeastC ー ass : NSObject ( vo 土 d ) c て @end @interface CatC lass BeastC ー ass (void)cry; @end void f( ) CatClass *theCat = [ [CatClass alloc] 土 n 土し [theCat 0 て y ttheCat release]; @end CatCIass オプジェクトで wa ⅸメソッドが使える CatClass * theCat = [ [CatClass alloc] 土 ni し [theCat walkJ; [theCat releasel; 146 C MAGAZINE 2001 6

8. 月刊 C MAGAZINE 2001年6月号

C プログラマのための C + + 入門 実践 0 + + ゼミナ→レ コンストラクタとデストラクタ 吉野智興 第 3 回 前回でグローバルなオブジェクトの生成と消去に 隠された C + + の内部的な処理の話が済みました。 今回も C + + の特徴である「コンストラクタ」と「デ ストラクタ」の話を進めていきましよう。 静的なオブジェクト 前回のグローバルなオプジェクトの生成 について補足があります。 C がそうであっ たように , C + + もそのソースファイル内だ け , あるいは関数内部でだけ有効な静的な 変数を持っことができます。キーワードで ある sta ⅱ c を伴った変数宣言がそれです。 List 1 のプログラムで宣言されている G および L は , それぞれコンストラクタとデ ストラクタの呼び出しをコンパイラが生成 します。このように変数がコンストラクタ やデストラクタを持つ場合は , その変数が 定義されたときにコンパイラがそのコンス トラクタとデストラクタの呼び出しを行っ てくれます。プログラマがとくに心がけな くてもコンパイラが何らかの処理を行うと いうのは C 言語にはない C + + の特徴のひと つでもあります。 Fig. 1 がその実行結果ですが , G, L どち らの変数の生成 , 消去に伴うものかは List 1 のプログラムではわかりません。これを 明確化するには「引数を持ったコンストラ クタ」の知識が必要ですが , その前に c で の自動変数 ( auto ) に相当する変数でのコン ストラクタ , デストラクタの扱いを勉強し ましよう。 一時的な変数 C や C + + は変数の宣言を強要する言語で す。変数は宣言することで初めて使えるよ うになり , 定義することでメモリあるいは CPU のレジスタ上にその実体を持ちます。 c では前節の「静的な変数」以外の変数はす べて一時的な記憶領域に確保されます。そ の記憶領域は通常は CPU のスタックと呼 ばれるメモリ上の領域であったり , CPU の レジスタそのものであったりします ( コラ c 十十 test . cc ー 0 test Fig. 1 List 1 の実行結果 ム 1 ) 。 OK,close OK,close Hi,I am Myclass Hi , I am Myc lass . /test 宅 コンストラクタ , デストラクタを使ったプログラム例 #include く std 土 0 上 > class MyCIass public: MyCIass(void) ¯MyCIass(void) static MyCIass G; main ( ) { fprintf { fprintf (stdout, (stdout, ″日 i , I am MycIass%n" "OK,close%n" ) 引数を持ったコンストラクタを使ったプログラム例 MyClass 引 0b 引 ( ”引 0ba げ -MyClass(void) { if (mes) fprintf (stdout, "%s ended*n%mes) MyClass(char *init) { mes = init; MyCIass(void) { mes = の fprintf public: char *mes; class MyCIass #include <stdio.h> static MyClass も一 (stdout, fprintf MyCIass Auto("Auton static MyCIass BIockStatic ( ”引 OCk Static main( ) static MyCIass LocaIStatic("LocaI Static" "Hi, I am Myclass%n") ”宅 s started%n", mes) (stdout, 実践 C + + ゼミナール 61

9. 月刊 C MAGAZINE 2001年6月号

ス化」を行います。改めて MainMenu. nib の ということです。後で実際のコードを見る ControIIer 」クラスを作成し , このクラスに lnstances タブを選ぶと MyController がアイ とわかりますが , OutIet はインスタンス変 Outlet (myV1ew) と Action (testl: と test2:) を コンになっています (Fig. 14 ) 。 数に実装され , Action はメソッドに実装さ 追加します (Fig. 12 ) 。この OutIet と Action 次に , Fig. 15 に示すようにオプジェクト とは簡単にいうと , れます。 同士の結線を行います。ここで作成してい この状態では , MyController は単なるク このクラスが外部参照した ・ Ou et ・・・ るサンプルプログラムでは , いオブジェクトのポインタ ラスにすぎず , MainMenu. nib がロードされ ( 1 ) myController の myView Outlet このクラスに対して外部か た段階でインスタンスにならないため , Fig. ・ Action ・・ 13 のようにして MyController の「インスタン MyWindow の MyView らアクションメッセージを受け取る (2)Test1 メニュー Fig. 15 オブジェクト同士の結線 → myControIIer の testl : Action (3)Test2 メニュー (a)Test1 ボタンから MyCont 「 0 Ⅱ e 「に結線する → myControIIer の怕S12: Action Ma 新 M 印ル . n 山 ( 4 ) MyWindow の Test1 ボタン stan ( 25 Classes Sounds lmages → myControIIer の testl : Action ( 5 ) MyWindow の Test2 ボタン → myControIIer の test2: Action の 5 か所を結線します。すべての結線が終 わったら , メニューから [CIasses] → [Creat e FiIes... ] を選択して MyController と MyV1e w に関するファイル (MyController. h , MyVi ew. h , MyController. m , MyView. m) を新 規作成し , プロジェクトに追加します (Fig. 16 ) 。 を 0 0 0 物 0 へ ル を 「 i [ R に spond 円・ 「ⅱざ 5 Owner MyWindow MYCO 「引厄 r 1 Test2 List MyView. h ( 新規状態 ) #import <Cocoa/Cocoa. h> @interface MyView : NSView @end ↓ ( c ) 結線完了 ( b ) 結線の種類を選び Connect ボタンを押す NSBu on 新 fO Connections NSBu on 新 Connections Outlets ね rg に t fO rmatte r menu nextKeyView Actions testl: t に 5t2. Outlets ね「 9 に t formatter menu nextKeyView 肥駐 1 : 5t2. List MyView. m ( 新規状態 ) #import MyView. h" @implementation MyView Destin ation 50u 「 ( を Destination 財 y ( 00 引厄 r. stl 50u 「 ( を ね rg にて List MyController. h ( 新規状態 ) #import <Cocoa/Cocoa. h> @interface MyControIIer : NSObject IBOutIet id myView; (IBAction)test1: (id)sender; (IBAction)test2: (id)sender; @end Connect Disconnect 50 C MAGAZINE 2001 6

10. 月刊 C MAGAZINE 2001年6月号

バターン文字列を返す flags フラグを返す match(str) self = = st 「 st 「に対してマッチングを行う 今回はモジュール関数にしたので , 「モジ ュー名ー関数名」という名前に変更してい ます。 また , メソッドの引数の省略をサポート するために fnmatch-fnmatch ( ) 関数の引数 は f—fnmatch() とは異なるものになってい ます。 argc で与えられた引数の数を , argv で引数の配列を , self でレシーバを受け取 ります。与えられた引数の数のチェックな どは自分で行ってもよいのですが , rb_sca n ー args ( ) という便利な関数が用意されてい るので , こではそれを使っています。 rb-scan-args ( ) は第 3 引数で与えられた フォーマットに従い , argc , argv をチェッ クします。このフォーマットは 1 つ目の数 字が最低限必要な引数の数 , 2 つ目の数字 が付加的な引数の数となっており , 2 つ目 の数字は省略可能です。また最後に " * " が 指定された場合は , さらに任意の数の引数 を受け付けることを示しています。この場 合は " 21 " なので , 最低限必要な引数が 2 つ で , 付加的な引数の数は 1 つです。第 4 引数 List 3 に対応する extconf. 「 b # ! /usr/bin/ruby require nmkmf" 迂 have—header("fnmatch. h") create—makefile("fnmatch") Fig. 1 WildCard クラス 〇クラスメソッド new(pattern, flags = 0 ) W ⅱ dCa 「 d オブジェクトを生成する 〇メソッド pattern to s 以下は VALUE 型の変数へのポインタを指 定し , 解析された引数はこの変数に格納さ れます。ここでは pattern に最初の引数 , st ring に 2 番目の引数・・・・・・といったぐあいに なります。 rb-scan-args() は実際に与えられた引数 の数を返します。この値を基にⅡ ags が与え られた場合はそれを int に変換したものをⅡ に代入し , 与えられなかった場合は fl に 0 を 代入しています。 あとの処理はほば前回の f ー fnmatch ( ) と 同じですが , rb_eRuntimeError の代わりに eFnMatchError を利用しています。 lnit fnmatch ( ) まず , rb_define_module ( ) で FnMatch と いうモジュールを作成し , mFnMatch とい う変数に代入しています (mFnMatch の m は module の m です ) 。 rb—define module ( ) は モジュールを作成する関数で , 引数にはモ ジュール名を指定します。改良版 fnmatch ライプラリではメソッドや定数や例外クラ スなどは , すべて FnMatch モジュールの下 に定義しています。 rb define—module—function ( ) はモジュー ル関数を定義します。引数はほとんど前回 利用した rb_define-global-function ( ) と同 じですが , 第 1 引数にはモジュールを指定 し , それ以降の引数が 1 つずつ後ろにずれ ています。引数の数は -1 を指定しています が , これは可変長引数を配列で受け取ると いう意味です。 rb-define_const ( ) で定数を 3 つ定義しています。前回は FNM NOESC APE という名前で定数を定義していました が , FnMatch::FNM_NOESCAPE では冗長 なので , FnMatch::NOESCAPE という名前 に変更しました。最後に rb_define_class u nder ( ) で FnMatch::Error という例外クラス を定義しています。第 1 引数はクラスを定 義するモジュール , 第 2 引数はクラス名 , 第 3 引数はスーパークラス ( この場合は Stan dardError) です。 の本設計の変更 さて , こまで fnmatch 拡張ライプラリ の改良をしてきたわけですが , 多少の変更 はあるものの , 基本的には fnmatch という 関数的メソッドを提供するというインタフ ェイスはそのままでした。せつかくオプジ ェクト指向言語を使うのですから , 思い切 って基本設計を変更し , WiIdCard というク ラスを定義することにしましよう (Fig. 1 ) 。 名前も wildcard 拡張ライプラリとします。 wildcard ライプラリでは , マッチングを 行うために wc = WildCard. new()* . h つ nstdio. h") p wc. match()* . h ” のように [W11dCard オプジェクトの生成 ] → [ マッチング処理 ] という 2 つの段階を踏む ことになります。 のための基礎知識 前回も簡単に触れましたが , 拡張ライプ ラリで定義されたクラスのオプジェクトも 含めて , C で Ruby のオプジェクトを扱うた めには VALUE というデータ型を利用しま す。この節では一歩進んで , V. , UE とはど んなデータ型なのかといったことをお話し ます。ただ , V. 用 IJE が実際にどのように機 能するのかを知らなくても拡張ライプラリ でクラス定義を行うことはできるので , わ からない部分は読みとばしていただいても かまいません。 VALUE の実体 VALUE 型は ruby. h で定義されています。 typede f uns igned long VALUE ー という定義を見ると , V, 用 XJE の実体は uns ignedlong であるということがわかります。 でもただの unsigned long でどうして Ruby Ruby マスターへの道 95