演算子 - みる会図書館


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

1. 月刊 C MAGAZINE 2001年6月号

standard slist の挿入 List iterator insert ( iterator —Where , const { / / -val を -Where に挿入 -Insert(-Where. -Mypnode( ) , -val て e 加て n (-Where); } void insert(iterator —Where, size—type —count, const { / / count * -val を -Where に挿入 size—type —Countsave —Count ー try { fo て 0 く—count; —Insert(—Where. —Mypnode( ) , —val) ー } catch { fO て—count く _countsave; 十十 _Count) -Erase(-Where. -Mypnode( ) リ / / 挿入の取消 t 社 0 町 } } temp ー ate<C ー ass —lter> void insert ( iterator —Where , —lter —First , —lter —Last ) { / / [-First, -Last) を -Where に挿入 —lnsert ( —Where , —First , —Last , —lter—cat ( —First ) ) template く class —lter> void —lnsert(iterator —Where, —lter —Count, —lter —val, —lnt—iterator—tdg ) { / / -count * -val を -Where に挿入 insert(—Where, (size—type)—count, (const —TY&)—Val ) template く class —lter> void —lnsert(iterator —Where, —lter —First, —lter —Last, input—iterator—tag ) { / / [-First, ー s 日を -Where に挿入、入力反復子 size-type —Num = try { iterator —Here = —Where; for 信—First ! = —Last ー十十—First , 十十—Num , 十十—Here ) —Insert(—Here. —Mypnode( ) , *—First); } catch ( for 信 0 く—Num; --—Num) -Erase(-Where ・ -Mypnode( ) / / 挿入の取消 t ね ro 町 } ) temp late く c lass —I ter> void —lnsert(iterator —Where, —lter _First, _lter _Last, forward—iterator—tag ) { / / [-First, -Last) を -Where に挿入、前方反復子 —lter —Next = —First; try { iterator —Here = —Where; for —First ! = —Last; 十十—First, 十十—Here ) —Insert(—Here. —Mypnode( ) , *—First); ) catch { for 信—Next ! = —First; 十十 _Next) -Erase(-Where. -Mypnode( ) / / 挿入の取消 throw; )) void —Insert(—Nodeptr const —TY& —val) ( / / -val を *-ppnode に挿入 —Nodeptr —Newnode = try { —lncsize(l); —Newnode = —Buynode(*—Ppnode); —Mybase: :—AlvaI . construct(&—MyvaI(—Newnode) , ー v 引 } catch { if (—Newnode ! = 0 ) { / / 割り当て成功、コンストラクタは失敗 ——Mysize; -Freenode(—Newnode); } セ社 ow ー } if (-Next(-Newnode) —TaiI = / / 新しい末尾 *—ppncde = ー Ne ) -—count ) slist の削除 LiSt void —Erase ( —Nodeptr *—ppnode ) { / / -pnode の要素を削除 if (*-ppnode ! = 0 ) { / / end の先でない。削除しても安全 —Nodeptr —pnode = —Next(*—Ppnode); if (—Pnode = = 0 ) -TaiI = の / / 末尾の削除、新しい末尾は未知 -Mybase: :-AlvaI . destroy(&—MyvaI (*-ppnode) *—Ppnode = ー ---Mysize; iterator erase ( iterator _Where ) { / / -Where の要素を削除 -Erase(-Where. ユ靼n2e( ) return (-Where); } iterator erase(iterator —First, iterator —Last) { / / [-First, -Last) を削除 fo て ( 引—Done = —First = = —Last; !—Done; ) { / / -First を削除し、それがなくなる前に -Last をテストする if (&-Next(*-First. ユ加n2e( ) ) = = -Last. -Mypnode( ) ) —Done = true; erase(-First); } / / ー F 辷虻は削除した要素の次のものを指す return ( —First な時間複雑性を示すことと , 反復子の挙動 を単純にするのと , どちらがより重要な原 則だろうか。私は前者がより重要だと判断 した。その理由は 2 つある。まず第 1 に , 時 間複雑性の要求は , 標準 C + + ライプラリに 組み入れられた STL クラスとアルゴリズム を通じて , かなり厳しく位置付けられてい る。第 2 に , 反復子の挙動については , ほ かのいくつかの場所ですでに疑問符が付け られている。 たとえば , ・ deque 先頭での要素の挿入は , それ以 前に begin ( ) が返した反復子を無効に する。また , 末尾での要素の挿入は , した要素の 1 つ前の要素を指す逆方向 それ以前に end ( ) が返した反復子を無 反復子もしばしば無効になる。これで 効にする。テンプレートクラス vector 驚かないなら何に驚けばいいのか すでに幅広く破られている原則を破るこ にも同様の問題がある。しかし , map, とはそれだけ容易であることを説明した。 set, 双方向リストにはこの問題はな 原則を破ることが幅広く支持されているこ い。 vector には , さらに内部への挿入 との維持の助けになる場合は , なおさらそ について問題がある。あるコンテナを 別のコンテナに切り換えるときには , うだ。 正しく使うための規則を守るようにす テンプレートクラス slist の出荷開始まで でに注意しなければならない状態にあ それほど時間をかけたくないと思っている。 とくに , ハッシュ表の場合のように C + + る ・逆方向反復子も , 隣接する反復子を格 の業界が別のオプションの集合を試そうと 納している。要素を削除すると , 削除 する前に出荷してしまいたい。 / 9 Standard C ℃ + +

2. 月刊 C MAGAZINE 2001年6月号

a 言語仕様第 2 版』翳 4.5.3 ) , おおま・かには次 の 3 種類を考えてください。 ・フィールドとしての変数 ・ローカル変数 ・パラメータ ( 引数 ) としての変数 これらは「プリミテイプ型」に限ったこ とではなく , 次に話す「参照型」でも共通 します。まずはプリミテイプ型を題材にし て見ていきましよう。 ーフィールドとしての変数 クラス中でフィールド ( 前号参照 ) となる 変数です。 List 2 (Physique. java) を見てく ださい。これは Physique( 体格 ) を記録す るクラスです。 Physique クラスの中に int 型の age , float 型の height , double 型の weight というフィールド変数があります これはクラスの中と外では使い方が違い ます。クラスの中 , つまりクラスで定義さ れているメソッドやコンストラクタの中で は , 11 ~ 13 行目のように単独で使うこと ができます。 クラスの外で使う場合 ( あるいは , クラ スの中でも static メソッドの中では ) , まず Physique 型のオプジェクト ( 前号参照 ) を作 らないと使えません。 Physique terao ー terao = Physi e ( 38 , 185. OF , 113.0 とすると , terao. age , terao. height , terao. weight というふうに使えます。使えるとい うのは , たとえば , terao. age = 2 のように代入できるし , x = セ e て ao. height * terao. weight; のように値としても使えるということで す。オプジェクトとフィールド名をドット でつないだものが 1 つの変数のように働き List 4 : 3 : 3 ます。 ーフィールドの修飾子 こでフィールドのアクセス可能性につ いて触れておきます。前回 , 「オプジェク ト指向では , フィールドを直接触るのは品 の悪いことだ」と言いました。品の悪いこ とが起きないように , フィールドをガード することができます。フィールドの宣言の ときに修飾子を付けて , どの程度まで触ら せてもいいかを , すなわちアクセス可能性 を指定できます。 アクセス可能性を決める修飾子 ( アクセ ス修飾子 ) には public , protected , private の 3 つがあります。また , これらを付けず に宣言してもよいため , アクセス可能性に は 4 つの状態があります。 ・ pub ⅱ c アクセス 公開してもよいことを示します。これを 付けて宣言したフィールドは , ほかのクラ スから自由に使えます。もちろん自分のク ラスの中からも使えます。 例 : public int ・ protected アクセス そのクラスの中とそれを継承したクラ ス , および同じディレクトリ中の別のクラ ズ注 1 ] から使えます ( 継承については後の回 で説明します ) 。 例 : protected bo 引 ean f ね ・デフォルトアクセス 何も付けずに宣言するとこの状態になり ます。そのクラスの中と , 同じディレクト リ中の別のクラス [ 注 1 ] から使えます 例 : doub 厄 val ue; メソッドの例 1 : / / メソッドの例 2 : double average(double x, double め double z) { doub le sum = x 十 y 十 z ー return sum / スタートアップ Ja a ) ava 言語事始 [ 注 1 ] 正確には「同じバッケージ中の別のクラ スから」。バッケージも後の回で説明します。 ・ private アクセス 自分のクラスの中でのみ使えます。 例 : private char ch; 今の段階では , 継承も , 複数のディレク トリ ( パッケージ ) を使ったプログラムもま だやっていないので , p ⅱ vate 以外は実質的 に同じになります。ただ後の回で使うので 覚えておいてください。 ところで , フィールドに付く修飾子には アクセスを制御するもの以外にも sta ⅱ c , nal , transient , volatile の 4 種があります。 こでは static とⅱ nal についてだけ見てお きます ( あとの 2 つはちょっと特殊な状況で 使われます ) 。 ・ static 前回も説明したとおり , static が付いた フィールドはクラスに 1 個だけ存在し , そ のクラスのオプジェクトで共有のものにな たとえば , 可になります。 ・ final ります。 これが付いたフィールドは , 書き込み不 final int x = 10 の とだけ値を保持しておきたいときなどに使 す。複雑な計算をするメソッドで , ちょっ メソッドの中で一時的に使用する変数で では次にローカル変数について。これは , ーローカル変数 きに改めて解説します。 っと違うところもあるので , メソッドのと けることができます。ただし , 意味がちょ ちなみにメソッドにも上記の修飾子を付 ん。 C 言語の const 修飾子に近い意味です。 x = 200 ; のように書き込むことはできませ とあれば , a = x; のようにはできるけれど , スタートアップ Java います。たとえば List 3 の average メソット 6 /

3. 月刊 C MAGAZINE 2001年6月号

Standard 構築し , ほとんど予告もなしに提案したの は偶然ではないのだ。 Beman の夜のセッションでは , ハッシュ 表を今後の標準 C + + 改版に加えるべきかど うかで若干ムダな時間を使ったが , 参加者 はその表記に関心を持った。というか , 議 論の大部分はハッシュ表を実装するテンプ レートコンテナが表現する外部インタフェ イスに費やされた。私は , Musser の実装は を幅広く用いられているが , 現在利用可能な ものはそれだけではないことを指摘した。 私自身も 1 , 2 年前に本連載で議論したハッ シュ表を書いた ( 本誌 2000 年 1 月号『ハッシ ュ表』 ) 。私の会社である , Dinkumware, Ltd. は , Dinkum C + + Library の一部として これを追加してコンパイラ業者に出荷して いる。 Microsoft V1suaI C + + のアップグレー ドバッケージの一部として個人がインター ネット経由で利用することもできる。 私のものは , Musser の外部インタフェイ スに正確に一致していなかった。むしろ , 私は , 自分が書いたハッシュ表を既存の se t / m 叩コンテナに似るようにしようとした たとえば , タの必要性をなくした シュ再計算の際に指定すべきパラメー strategy) を利用し , 全テーブルのハッ ・段階的成長戦略 (incremental growing ートする シュ表コンテナは双方向反復子をサポ 在するコンテナすべてと同様に , ハッ より , 標準 c + + ライブラリにすでに存 双方向リンクリストを使った。これに ・下部表現に , 単リンクリストではなく ーを使い , 要素すべての領域を定める 用 map に対して , この関数は等価なキ なる。 / 、ツシュ mu は iset やノ、ツシュ mu 「 ange を上手に定義することが可能に った。これにより , メンバ関数 equal_ うに順序付け規則として ope 「 ator くを使 はなく , 既存の se map コンテナのよ ・ Musser が使った伝統的な ope 「 ato 「 = = で 第 たほど問題にならないことだ。デフォルト のテンプレートパラメータとハッシュ表の 基本的操作にとどまる限り , これら 2 つの 実装は互いに交換可能であり , また , 既存 の木構造べースのコンテナとも交換可能で たちはみな , 経験から利益を得ることがで だ。そして , 難しい決断を後で行う前に , 私 ある変種で実験する好機であるという理由 それが , それぞれ違うが , かなり互換性の るに違いない細かい点であった。そして , 来の C + + 標準に追加する以前に合意に達す あった。それらは , 人々がハッシュ表を将 級のハッシュ表ユーザの関心が向く部分で ある。設計上の決定のほとんどは , より上 きる。 表の基本要素としても利用されている。 に述べたように , これは Musser のハッシュ 幅広く採用されているものである。私が先 + + ライプラリに対する非標準の拡張として トコンテナであった。これもまた , 標準 C は , 単リンクリストを管理するテンプレー がますます強くなった。そのリストの筆頭 さらに拡張することを考えたいという思い センスしている標準 C + + ライプラリに対し その会議から帰ってから , 私たちがライ ー小さなリスト見つけた とみなされなかった。 しかった。違いは単にどちらでもいいもの が好意を持って受け止められたことがうれ のところ , かって私が行った設計上の選択 ントロールされた改革はいいものだ。結局 って改善され続けてきているのだ。よくコ ョンでさえも Silicon Graphics のメンバによ ナルのテンプレートクラスの現在のバージ 表明はなかった。実際には Musser のオリジ 即座に標準としようとする感情的な意見の かったこともうれしかった。最初の実装を った。また , これらの違いが論点とならな 解に真剣に努力したことを私はうれしく思 が , 両方の設計と違いの裏にある理由の理 その夜のセッションでの議論で , 参加者 見たところ , 標準 C + + ライプラリにこの ような追加を施す必要はない。すでに双方 向リスト ( テンプレートクラス list) が存在 し , 単リンクリストから得られる機能のス ーパーセットを提供している。しかし , 単 リンクリストが必要な理由が , 少なくとも 2 つある。 ・単リンクリストはリストノードそれぞ れの要素の値につき , リンク 1 つだけ を格納する。双方向リストは 2 つのリ ンクが必要なことは明らかだ。状況に よっては , 記憶容量削減の要求が重要 な場合もある ・普通は , 単リンクリストのほうが要素 挿入 , 削除のためのコードが簡単にな る。状況によっては , 実行時間やコー ド領域削減の要求が重要な場合もある 双方向リストの場合 , 支払わねばならな いコストは , 反復子にある。双方向リスト の場合 , 明らかに双方向反復子 ( bidirec ⅱ 0 皿 literato を十分サポートできるが , 単リ ンクリストは前方反復子 (forward iterator) だけをサポートする。もちろん , 逆方向反 復子 (reverse iterator) も守備範囲外である。 てハッシュ表が広まるにつれ , 昔の決定を ある。それで , とくに , 非標準の拡張とし ならないという必要性もないという現実が れば , どうしても私たちから買わなくては 供されるライプラリで満足できないのであ という義務はない一方で , 顧客のほうも , 提 るものなら何でも提供しなくてはならない のだが , ライプラリ業者として顧客が求め すべてを提供することはほとんどできない の要望が何件かある。実際は , 求めるもの もかかわらず , 顧客からの単リンクリスト の双方向リストの改善に注力した。それに ( 本誌 2000 年 11 月号『リストの改良』 ) , 既存 た。実際には , 以前本連載で触れたように ると , 私は何年も前に自分を納得させてい するにはこの潜在的な節約は中途半端すぎ テンプレートクラス丸々 1 つぶんを保証 子が必要だからである。 この魔法の裏には , 少なくとも双方向反復 よい知らせは , これらの違いは思ってい 2 1 6 / 6 c MAGAZINE

4. 月刊 C MAGAZINE 2001年6月号

タンスへのポインタを持っていました八 0 フ 回作成した marbrow では , 子コントロール として抱える各インスタンスへのポインタ は直接持ちません。 WMNG_WIND * mw mngW1nd が , ウインドウ管理マネージャの ウインドウデータへのポインタで , ら各コントロールへのリンクがたどれるよ うにしています。 また marbrow では , 1 ウインドウに複数の プラウザを配置できるため , クロームイン スタンスは各プラウザシェルごとに生成し ます。そのため , クロームへのポインタは , Li st 4 MWind クラスのコンストラクタ MWind: :MWind( WMNG—WIND *wmngwind ) ウインドウクラスではなく , ルクラスで持ちます。 生成 / 破棄 プラウザシェ MWind クラスのコンストラクタでは , メ インウインドウの作成 , プラウザシェルを 含む子コントロールの作成と初期化をすべ てコントロールします (List 4 ) 。 メインウインドウの作成 , ルートコント ロールの作成などは , Macintosh で行われ ている通常の方法で行います ( List 4-(a))0 開発環境やプラットホームが変われば , そ ネットワ - クプログラミンクのアトリエ テレートし , 各オプジェクトを生成します。 mWmngWind の子コントロール配列をイ に移動しています。 はプラウザシェルクラスのコンストラクタ をプラウザごとに生成するので , その処理 を行っていますが , marbrow ではクローム PPBrowser では , ここでクロームの生成 ンスタンス生成します ( List4- ( c ) ) 。 定します。続いてべースウィジェットをイ ャのウインドウデータ (mWmngWind) を設 List4-(b) では , ウインドウ管理マネージ れに合わせた処理を行うことになります。 hMinde:Create",ü ! れ 0 れ e ” newnoea MemErro : mWmngWind( wmngwind ) , mTarget( ・ NULL ) , mTargetBrow( NS—IMETHODIMP MWind: :Create( ) create( MBrow: :GetAutoDet( &gAutoDetMenuItem ); て OW : :GetCharset( &gCharCodeMenuItem OSErr Rect rect ー WindowPtr window; Contro ー Hand ー e rootContro 嵭 を " れ tsparan rect mWmngWind+bounds ・ 、 / * Create 0 曾 / 、、 ExtErr(: er てい」 CreateNewWindow e てて or ! ! " 土れ d C で eate い ! none を ) ; ー、駐ぐ err ) ( kWindowStandardDocumentAttributesi & て eC 土れ dow ) をて。洋。 CreateNewWi れ dow ( い kDoc ⅱ me れ tW1 れゎ第第 err = CreateR00tControl ( window, & て 00tCon に ro ー if( e てて ) { err GetR00tControl(. window, & r00 と Co れセて 0 い ) す な R00 セ Con い 0 ー * / ((WindowPeek)window)+WindowKind ま厭工ー BROW を ~ ノ * Set WindowKind な 犀 9 叩ら SetRGBCOIor( color, 192 を 192 , 192 ) 引 RGBCOlor 00 て一 ノ * Set Window Content c 引 0 工 * み SetWTitIe( ndo 町第蕚 pma で b て ow を / * Set 凵 e * / "MWind: ;Create% ”れ one ″リ EXtErrC e てで CreateRootControl e てて 0 て物 土 f ぐ e てて ) { eate- と mWindow ま do—CreateInstance(kWindowCID & てⅵを nsresu ー t を rv; mWmngWind->rootContro ー = て 00 セ Cont て 0 リ mwmngwind->wind = window% break 3 当 E%tErr(' MemErtor() j•new MButt e てて 0 て。「いを ifWmbutt ) イ u ま曲し言 0 u ぐ mwnngwind, cnt を ) 鷺 break; t で ( 阨 m て 0 ヨ ) い % ねて 0 if( lmstat ) ( MStat 、 *mstat 言れ e 蘇 st 北ぐ mwmngwind, cn 日っす鷙 case CNTLTYPE—BROW: break; 社れ d : :CreateD@ä 0 れ e ) ExtErr( MemError( nnew MBfOW もてて 0 て ーは f い一 ! 曲て ) { 、 row * 曲て ow キれて 0 、 nwmngWind,cntl" PMWind:tCreatent7 one を ) break; 。、 0 S 1 nsRect て ( 0 , 0 xnxs ea e se 工 g MView WMNC—CNTLS WMNG—CNTLIT WMNG—CNTL *initFocus NULL ー cntl 8 = mWmngWind->cntl 町 cnt は *cnt 嵭 mwmngwind->bounds. right mWmngWind → bounds. 厄 f し mwmngWind->bounds. bottom ー mWmngWind->bounds.t0P); → wind, て , for( cnt は t = 凵 s ・ 29 加 ( 嵭 cn しはい = c れ凵 s. e れ d ( わ十十 c 豆凵辻 ) { cntls ま mWmngWind-»cntIs; 1 eateSe れ s れ猷し nsnul し nsnul しれ 9 u 料 s れ猷 l) 引 err TransitionWindow( window, 0 Wi 0 第 cnt ト >mview->FinighCreateSeIf(); 0 れい = * cn 日土 "MWind: :create", "Main Window" ExtErr( e てて , 師て ansi onw 土 ndo 響 e てて 0 て % 迂 ( err ) ( kWindowzoomTransitionEffect, kWindowShovrransitionActiont NULL ) f0 て ( cntlit=cntls. 0れ凵址!=Cn凵S. end( cn 凵 = *cntlit; switch( cntl->cntl—type ) { case CNTLTYPE—L(XA: ・ oca *mloca = れ e 曾 MLoca( mwmngWind, 十十 cn に lit ) ( cn 目 / * 工れ辻を ocus * / return NS—OK ー 技術を知って実践しよう ! ネットワークプログラミングのアトリエ 1 23

5. 月刊 C MAGAZINE 2001年6月号

Fig. 1 プリミティプ型と参照型 intx = 3 : Data y = new Data(3); 3 代入と変更 Fig. 2 List 5 の実行結果 ( 注 1 ) int など , 最初から定義されている型 参照 ( ポインタ ) での使用 の va の場合直接の使用 参照 ( ポインタ ) での使用 ℃言語の場合直接の使用 TabIe 2 プリミティプ型と参照型の相違 :Data value = 3 基本型 ( 注 1 ) 〇 プリミティプ型 〇 〇 集成体型 ( 注 2 ) 〇 〇 参照型 〇 List 6 2 : 4 : 6 : 8 : 9 : 10 : 11 : 12 : 13 : ) 14 : 16 : 17 : 18 : 19 : ) 20 : 22 : 24 : 25 : 26 : 28 : 29 : 30 : 31 : 32 : 33 : } スタートアップ Ja a Java 言語事始 インタフェイス型の例 ( Speak. java ) * Speak. java 5 : interface SpeakabIe{ public void speak( class Enshou implements SpeakabIe{ pub lic void speak ( ) { system. 0uしPてin凵れ(”百年目と思いました” 15 : class Kosan implements SpeakabIe{ public void speak( ) { system ・ ou し prin 凵れに今なんどきだい ? つ・ 21 : class Speak{ public static void main(String[ ] args) { SpeakabIe 町 S = new Enshou( s ・ speak( s = new Kosan( s. speak( ( 注 2 ) 配列型や構造体型など ーインタフェイス型 プリミテイプ型と参照型の相違はしつか り理解してください。とくに C から移って きた人は注意すべきところです。 C 言語と の比較を TabIe 2 にあげておきます。この 特徴は , 人によっては制限と見るかもしれ ません。しかしこれによって Java の言語と しての堅牢性が保たれているのです ( もっ とも SmaIItaIk 派からは「プリミテイプ型を 特別扱いするなんて汚い仕様だ」と言われ そうですが ) 。 ークラス型 これは前回も説明しました。ある「クラス」 を元にして作られる「オプジェクト」を保 持するための型です。 例 : Data d = new Data( クラスのインタフェイス・・・・・・つまり「ど ういうメソッドがあるか」だけを決めてお いて , そのメソッドを持っているクラスを 保持できるようにした型です。 これだけではわかりにくいので例をあげ ましよう。 List 6 を見てください。 5 ~ 7 行目 で class の代わりに inte ace が付いて宣言さ れているのがインタフェイスと呼ばれるも のです。 あ , それから今までは 1 つのファイルに 1 つのクラスだけを記述していましたが List 6 のように複数のクラス宣言やインタ フェイス宣言を記述することもできます。 ただしこれはあまりいいやり方ではありま せん。別ファイルにすると見にくくなりそ 。読者のみなさ うだからこうしたので・・ んが書くときは 1 つのファイルに 1 つのク ラスとしてください。 話を戻します。インタフェイス SpeakabI e では speak() というメソッドが宣言されて います。こうすると , speak() というメソ ッドを持っているクラスを Speakable とし て扱うことができるのです。クラス Ensh ou , クラス Kosan は , クラスとしては別で すが , どちらもインタフェイス Speakable を implements しているので , Speakable 型 として取り扱えるわけです。 インタフェイスについては , 回を改めて ー修飾子とデフォルト値 後にまとめて述べます。 配列型も参照型の一種です。これは少し ー配列型 詳しく解説します。 クトのフィールドには代入できるかもしれ ことはできませんが , それが指すオプジェ nal と宣言された参照型の変数に代人する ただⅱ nal の意味には注意してください。ⅱ 意味はプリミテイプ型のときと同じです。 ansient, volatile) を付けることができます。 ublic , protected , private , static , final , 仕 参照型にも , 先に述べたような修飾子 ( p ません。 スタートアップ Java 69

6. 月刊 C MAGAZINE 2001年6月号

特集 2 Mac 05X アフリケーション開発ガイド れたプロジェクトには main. m というソース C 特有のものですが , #include と同様 , ファ ジェクトの run メソッドを起動する関数で と MainMenu. nib などがあらかじめ登録され イルの取り込みを指示するものです。ただ す。詳細は Developer Help Center の「 NSAp し , 2 回以上 , 内容を取り込まないように p ⅱ ca ⅱ on 」を参照してください。 ています (Fig. 8 ) 。 main. m の中身は List 5 の します (#pragma once のあるインクルード とおりです。 1 行目の「 #import 」は Objective- もちろん , この中身のない main. m だけで ファイルをインクルードしたのと同じ結果 は真っ白なウインドウが 1 枚開かれるだけ ー a 旧 . m になる ) 。 でプログラムとしては何の役にも立ちませ NSApplicationMain というのは , 内部で ん。そこで , 次のステップに進むために アプリケーションオプジェクトの発生と , 「 Groups & Files 」の一覧に表示されている メインの nib ファイル [ 注 13 ] をロードし , アプ [ 注 13]Interface BuiIder によって生成され リケーションオプジェクトを nib ファイルの るファイル。 nib は NeXT lnterface Builder の頭文字をとったものという説が有力 所有者としてから , アプリケーションオプ Fig. 12 MyCont 「 0 Ⅱ e 「クラスの作成 ( a ) NSObject クラスを継承する MyCont 「 0 Ⅱ e 「クラスを作成する ・ 0 0 M M 。叫曲 as e & ・ lmages Sounds List #import く C000a / C000a. h > 土 n main(int gc , 00n8 セ char *argv[ ] ) return NSAppIicationMain(argc, argv); Fig. 10 独自ビュークラスの作成 ( a ) Classes タブに切り替えて NSView を選択する 0 0 0 MainMenu.nib a55 & images Sounds lnstances lnstances 田十十 v 工信 ng. 0 切 e ( t NSOb 第は Fi 「 5 【 R ponde 「 旧ⅲ 5P2 ( tO 「 旧 Pa には 0 NSM にれ 0 NSMenuItem NSResponder NSAppIication NSDrawer NSBox NSCI ゆⅥ ew ・ NSCon な NSBrowser マ マ 71 ・ 1 ・ 2 ・ マ SV NSArray NSM リい b に A 「 y NSCe 日 (b)Add Outlet と Add Action を選択して Outlet と Action を追加する Fo 「 m 誂し Subclass lnstantiate Edit ロ a 弱 Add Action ↓ 0 0 0 M M 今叫 ⅲ 5 ね n ( es ( iasse 、 jmages Sounds 0 、田、△ N50 切 t 0 ー 71 ・ F ⅳ st 5 po れ d 旧 5 は 1 ・ 2 ・ マ My ( 0 飛「 OII 0 破厄 t & myView A れ 5 t25t1. t05 に : NSA My ( 0 「 0 リ マ マ マ ↓ ↓ ( b ) メニューから SubcIass を選んで子クラスを作る 「 0 「 m ( は sses Classes Subclass lnstantiate Add OutIet ↓ ( c ) 作成した子クラスの名前を M iew にする 0 0 0 MainMenu.nib 5 ね n ( es ( & se 、 lmages Sounds 田十十 NSMenu NSMenultem NSResponder NSAppIication N SDrawer NSView NSBox NSCIipView NS 〔 on 引 マ マ マ MYView マ マ 47 MacOSX アプリケーション開発ガイド 特集 2

7. 月刊 C MAGAZINE 2001年6月号

では x , y, z の平均値を出すため , とりあ ミテイプ型の場合は , 直接値を保持してい メソッドに渡されるわけです。 えず合計を計算する必要があるのでローカ 修飾子として血 al を付けることができま ます。 ル変数 sum に合計を格納しています。 すが , 血 al が付いてない場合 , ほかの変数 List5 の 14 行目以降を見てください。 x を 変数に , y を変数に代入し , それから ちなみにこれは , 宣言されたメソッドの と同じように値を代入できます。たとえば , データとして正の値がほしいとき , 負の値 xx と yy の値を変更しています。実行結果 中のみに存在します。どういうことかとい (Fig. 2 ) を見ると , x が持つ値は元のままで うと , メソッドを使うたびに作り出され , が渡されてきたら x = - x ; と符号変換してか すが , y が持つ値は変わっています。プリ メソッドが終了すると消されるのです。 ら使うことができます。 ミテイプ型の変数の代入 , = x ; では x の 時的にメモしておくための変数なのです。 パラメータの変数は , メソッドから抜け 値そのもの ( ここでは数値 3 ) がに書き入 ローカル変数以外の変数は , 作り出され ると消されます。このへんはローカル変数 れられたのに対し , 参照型の変数の代入 , たときは TabIe 1 にあるデフォルトの初期 と同じと思ってください。 野 = y ; では y の指す『場所』がに書き入れ 値をとることになっていますが , ローカル 参照型 られたわけです。 y とは同じ『場所』を指 変数はデフォルト値で初期化してくれず , しているので , がその場所の内容を変更 明確な値を代入せずに使おうとするとコン すると , 当然同じ場所を指す y も変更され 参照型というのは , プリミテイプ型以外 パイルエラーになります。 た値になるのです。 のもので , 代表的なのはクラス型です。次 ローカル変数には修飾子として血 al だけ クラス型以外の参照型も同じであり , デ の 3 種類があります。 付けることができます。 ータを持っているオプジェクトを参照して ・クラス型 IJ ヾラメータとしての変数 いるので「参照型」というのです。 ・インタフェイス型 ・配列型 ところで , C 言語を知っている人はこ List 2 の Physique クラスのコンストラク で「ポインタ」を思い出すでしよう。 Java まず , これらがなぜ参照型と呼ばれるか タや , List 3 の average メソッドに与えるテ が登場したころ , 「 Java にはポインタがな を説明しましよう。 int 型の変数 x と , int 型 ータ , これを引数もしくはパラメータとい い」ということがよく言われました。しか を保持する Data 型 (List 4 ) の変数 y を考えま います。 Physique なら a , h , w , average す。この変数 x , y を , List5 の 7, 8 行目の し , 参照型というのが実質的にはポインタ なら x , y , z がそれにあたり , これも変数 ように宣言して初期化します。このとき , なのです ( C 言語のポインタとはいろいろ です。たとえば , な点で相違がありますが ) 。一方プリミテ イメージとしては Fig. 1 のようになります。 average ( 10.0 , 5 , 5 , 4.0 のように average 0 メソッドを使っている 前回話したとおり , クラス型の変数はどこ イプ型 , int とか double とか boolean とかに 関していえば , たしかにポインタはありま かほかにあるオプジェクトを指しているだ としたら , x には 10.0 という値が , y には 5.5 けで , 直接には値を持っていません。プリ という値が , z には 4.0 という値が入って , せん。 List List 5 Data を使い , プリミティプ型と参照型の違いを確かめる ( DataTest. java ) 4 int を保持するクラス (Data. java) 2 : * DataTest. java 4 : 5 : class DataTest{ public static void main(String[ ] args) { int x = Data y = new Data(3); System. 0uしPてiれ凵n( ” 10 : X : system. out. println( "y : 11 : 12 : 〃他の変数に代入し、値を変更する 13 : 土 n セ XX ま x; 14 : 15 : Data め′ = y; 16 : 17 : )Ⅳ . value = 5 ・ 18 : system. out.println()i 代入と変更” 19 : system. 0uし・ Pて土n凵nに 20 : system. out. Pて土nいnに を十 y. value); 21 : Y : 22 : 23 : * Data. java 2 : 3 : * int を保持するクラス 4 : 5 : 6 : class Data{ int value; 8 : / / 引数無しのコンストラクタ 9 : Data ( ) ( 10 : val ue = 1 11 : 12 : 13 : 〃引数有りのコンストラクタ 14 : Data(int x){ 15 : 16 : value x; 18 : } 十 y. value); 68 C MAGAZINE 2001 6

8. 月刊 C MAGAZINE 2001年6月号

Te 「 min アプリケーション Termin アプリケーションは , 典型的な UN Ⅸの CUI な開発スタイルで行えます。す なわち emacs のようなエデイタでソースを 編集し , cc でコンパイルするようなスタイ ルです。これとは別に Project Builder でも “新規プロジェクト”で T06 のカテゴリを選 ぶと , Termin 上で動作するプログラムを 作成できます。 Kernel 関係のドキュメントによれば , KerneIExtension とデバイスドライバ ーネルモシュール 御するために動的にロードされるカ バスに連結されているデバイスを制 ・デバイスドライパ・・・・・・コンピュータや コラム 7 その他の プログラム開発について Fig. 18 ・ KerneI Extension [ 注 A ] ・・・・・・再コン / ヾイル や再リンクをせずにカーネルに動的 にロードされるモジュール という OS の機能を動的に拡張する仕組み があります。 これらも Project Bu ⅱ der を使って開発し ます。興味深いトピックではありますが [ 注 B ] 誌面の都合上 , 今回は割愛させていただき ます。 なお詳細は HeIpViewer を立ち上げ [Deve loper Help Center] → [Kernel] の項目を手 がかりにしてください。 [ 注 A]kext という略称や拡張子が与え られている場合が多い [ 注 B ] デバイスドライバは I / 0 t とい うフレームワークを利用し , Embedde dC + + で開発するスタイルである ずです。 Objective-C のときと同様 , List 13 の MyV1ew クラスは白紙状態で , List 14 の MyControIIer クラスには lnterface Builder で 付け加えた Outlet と Ac ⅱ on が用意されてい ます。それぞれのファイルを List15 , 16 の ように変更します。プログラムの中身は Obj ective-C のものと , まったく同じなので解説 List 16 MyCont 「 olle 「 . java ( 変更後 ) / * MyControIIer * / import 00m. apple. 00C0a. foundation. import com.apple.0000a.application. * ー public c ね 88 MyControIIer { MyView myView; public void test1(Object sender) myview. changeTestFIag(2); public void test2(Object sender) myView.changeTestFIag(1); List 15 MyView. java ( 変更後 ) / * MyView * / import 00m. app 厄 . cocoa. fO ndat 土 on. も 土 mpo て t ・ com.apple.cocoa.application.も public class MyView extends NSView { 加セ mTest; / / 1 : で estl が押された , 2 : Test2 が押された if(mTest = = 1 Ⅱ mTest = = 2 ) { system. eてて . println( "drawRect."); public void drawRect(NSRect rect) { setNeedsDisplay(true); mTest = inFlag; if(inFIag ! = mTest) { system. eてて . println(") . System. eてて . print(inFlag); System. err. print("changeTestPlag(" public void changeTestFlag(int inFlag) mTest = 0 ・ system. err. print ー n ( "MyView constructor. super ( frame public MyView(NSRect frame) if(mTegt = = 1 ) { NSBezierPath thePath ー thePath = NSBezierPath. )else{ thepath = NSBezierPath. InRect(rect); thepath. fill ( NSCO て . て edCo て ( ) . set( クラスの Language を変更する (a) MyView の CIassInspecto 「を開く Edit ロ a55 を 5 FO 「 m 載 Layout Window T00 区 ・ 0 0 : 」 MainMenu.nib lnstances にね 55e5 lma Palettes Alignment Show C 0 Show 抦 fo Help 0 A 0 認 C マ MYView NSBo メ NSClipView NSCc 砒「引 NSBrowser NS Button NSPopUpButton NSCoiorWell NSI rnageView マ 4 ・ 3 ・ 3 ・ 10 ・ 8 ・ 8 ・ ↓ Java 0 切“ t Ⅳに ( 3 い ng い 9 を Attributes C 、、、 pe ロ 0 「 (b)Language を Java に変更する 5 イ C MAGAZINE 2001 6

9. 月刊 C MAGAZINE 2001年6月号

List 1 ↓ appDir / / lnit Embedding = do—QueryInterface(macDir); rv = NS—InitEmbedding(appDir, nsnull リ / / Make pref D 土て ec セ 0 て y nsMPFi ー eLocProvider * ー ocationprovider = new nsMPFi ー eLocProvider ー NS—ENSURE—TRUE い ocationProvider , NS—ERROR—FAILURE nsCOMPtr«ns I Fi ー e> て OOtD 土て一 rv = NS—GetSpecia lDi て ec に 0 て y ( NS—MAC—PREFS—DIR , getter—AddRefs 仕 ootD 土て ) / / Needed because things read default prefs during startup if( NS-SUCCEEDED(rv) ) { NS—WITH—SERVICE(nsIPref, prefs, kPrefCID, / / lnit pref NS—ENSURE—SUCCESS(rv, NS-ERROR-FAILURE); rv = locationProvider—>Initialize(rootDir, NS—ENSURE—SUCCESS(rv, NS—ERROR—FAILURE); ” ma て b て ow ” & て v / / reduce the font size here by hand / / HACK ALERT: Since we don't have prefs UI , prefs->ReadUserPrefs( prefs->Resetprefs ( ncou れ Ot get preferences service" prefs->SetIntPref("font. size. fixed. x-western", 9 prefs->SetIntPref( "font. size. variable. x-westernn, 12 ) ・ て ow : :UpdateBookmarkMenu( リ / * Bookmark Menu * / NS—ASSERTION(PR-FALSE, )else{ prefs->SavePrefFile( / / ShutDown preferences nsresu ー t rv; static void TermWebShell ( void / / 終了 return NS—OK ー short itemNo; Dia ー ogptr if( IsDiaIogEvent( event ) ) { / * Modeless Dialog * / if( event->what ! = れⅲ IEvent ) { ー / * Some Event * / VOid ProcessEvent ( EventRecord *event イベント処理 List 2 NS-TermEmbedding ( / / Term Embedding UMacUnicode: :ReleaseUnit( リ prefs->SavePrefFile( リ if( NS-SUCCEEDED(rv) ) { NS—WITH—SERVICE(nsIPref' prefs, で指定しています。この初期化を呼び出し た後に , 工ンべッディングのさまざまな処 理が行えるようになります。 同じく TermWebShell() がエンべッティ ングの終了処理です。ほかにプリファレン スのセープ , UMacUnicode のクリーンアッ プも行っています。 イベント処理 ProcessEvent() がイベント処理を管理す るメソッドです (List 2 ) 。 こでは Mozilla kPrefCID, &rv 特有の処理を行っています。イベントルー プごとに nsRepeater::DoRepeaters ( ) を , nu Ⅱイベントごとに nsRepeater::DoIdlers ( ) を コールします。実際のイベント実行処理は , DoEvent() で行います。 ンスタンスへのポインタ , クロームインス でほかに子コントロールとして抱える各イ 前述の PPBrowser ではウインドウクラス ットへのポインタを持ちます。 の Mozi Ⅱ a 的表現であるウインドウウィジェ 連のメンバ変数として , メインウインドウ す。 MWind クラスの定義では , Mozilla 関 List 3 にウインドウクラスの定義を示しま インドウクラス (MWind) 、 static MView* mviewClicked; WMNG—WIND *mWmngWind; public: / * Attribute * / virtual NMWind( MWind( WMNG-WIND *wmngWind ); public: / * Constructor, Destructor * / typedef Wiew 工 e て土 t ー private : class MWind : public MView ウインドウクラスの定義 List 3 &itemNo ) ) { lDlog *mmidlog の g : :FindByDIog( dlog if ( D 土引 ogSe 厄 c セ ( event , & 引 og , Repeater; :DoIdIers( / * DO Moz ldle * / DoIdle( event / * DO Äpp ldle * / )else{ / * 齟日 DoEvent( event / * handle event * / て eturn ・ if ( mmidl og *event 房 Event * / mmidIog->DoEvent( itemNO Repeater: :DoRepeaters( *event / * DO MOZ Repeat * / DoRepeat( event / * DO App Repeat * / . :PR—Sleep(PR—INTERVAL—NO-WAIT); return ・ MView MBrow *mTarget; *mTargetBrow; / * BrowserWindow * / public: NS—METHOD GetWidget( nsIWidget** awidget ) ー MBrow* GetBrowserSheII ( UInt16 id=CNTLID—ANY ) cons void GetTitIe( S し r255 title void SetTitle( S い 255 title リ protected : nsCOMPtr<ns IWidget> mwindow ー 1 22 C MAGAZINE 2001 6

10. 月刊 C MAGAZINE 2001年6月号

程式を解くのです。この式は Gauss-Seidel なんか使う必要がありません。単純にエレ メントへの比率でパッチのラジオシティを 分配するだけで計算ができます。これで , それぞれのエレメントの明るさを手に入れ ることができるのです。大きな単一バッチ では表現できなかった細かな明るさの変化 を , 代わってエレメントが取り扱ってくれ るのです。 動的な分割 この階層法のよさはこれだけでは終わり ません。これで手に入ったエレメントの明 るさが , どうも気にいらないとしましよう。 たとえば , Fig. & ( a ) のように隣接する部分 で極端に明るさが変化している場合などで す。そのときは迷わずエレメントをさらに 分割してしまいましよう。エレメントの子 供としてさらにエレメントを作る方法もあ りますが , こではパッチの新たな子供と してエレメントを増やすことにします。 1 つのエレメントが 2 つになったとして , 元のエレメントのフォームファクタと , 新 たな 2 つのフォームファクタの和とは等し くなるはずです。ほかのエレメントには影 響を与えないので , 増えたエレメントに関 してだけ , Fw を計算しなおすことになりま バッチ同士のフォームファクタ (a) バッチ同士のフォームファクタ ←おーー (b) ( a ) を使って解くラジオシティの方程式 B=E +. QEBF (c) それぞれのエレメントの明るさ 召 =E + p 召 F Fig. 10 余剰べクトル r(0)=KB(0)-E す。 こうやってエレメントを増やしたうえで 各エレメントの明るさを計算するわけです が , やり直さなければいけない作業は , 前 段の最後の処理 , パッチからエレメントへ の分配だけになります。もう大きな連立一 次方程式を解く必要はないのです。パッチ が手に入れたラジオシティをエレメントで 分配する手順は , 全部が落ち着いてうんと いうまでエレメントたちだけで繰り返すこ とができるのです。もちろん分割 , 結合も 自由自在です。なんとも巧妙な作戦ですよ ね。 分割の判断基準と方法 分割にまつわることとして , 分割の判断 基準や方法についても少し触れておきまし よう。隣接するエレメントの明るさが極端 に違い , 不連続 (discontinuity) がある場合 はもちろんですが , ほかにも参考になる情 報がいくつかあるのです。 まずは , 前回説明した余剰 ( residual) べ クトルで , Fig. 10 のようなものです。繰り 返しの手順の中で登場して , 前回はあまり 脚光を浴びなかった余剰べクトルですが , ここにきて利用価値が出てきます。このべ クトルの中には , 何度か反復を繰り返して もなかなか収束しない要素が見つかる場合 があります。そういったときは対応するパ ッチの形自体に無理があるんじゃないかと いう信号として受け止めることができます。 これとはまったく別の方法で分割の判断 をすることもあります。たとえばレイトレ ーシングと併用しているときなど , その明 るさとの比較をそのまま参考にして分割の 決定を行うのです。これはどちらかという とパッチ生成の段階で行うことが多いので すが , レイトレーシングに限らず , 貼られ るテクスチャの特性やパッチの接続のしか たから類推することもあります。 分割の方法で興味深いものとして , シャ ドウポリューム ( shadowvolume ) を用いる 方法があります。問題であった影の取り扱 30 ~ mm Enter The 3D Programming 1 1 9 しよう。 インバースキネマティクスを攻略してみま どもあまりくわしく知られていない話題 , 取り上げます。これも名前はよく聞くけれ 気がしますが , 次回はまったく違う話題を さて , 毎回同じことを言っているような と思います。 れている話題なので , 一度検索されるとよ そのほかにも Web 上などで盛んに論議さ タの議論なんかが飛び出してきます。 が , 根気よく読んでいるとフォームファク 本棚の肥やしになりがちなシリーズです RESS "Graphics Gems ト V", ACADEM ℃ P いものが多くあります。 いる良書です。ほかのトピックスも興味深 コンパクトにつばを押さえて説明されて Addison WesIey Techniques ” , 旧 BNO -201-54412-1 , "Advanced Animation and Rendering くしてくる本です。 羅されています。読んでいるだけでわくわ ラジオシティに関する議論がほとんど網 aufumann Publishers sis", 旧 BNO -12-178270-0 , Morgan K "Radiosity and Realistic lmage Synthe 献をあげておきます。 興味を持たれた方のために , 主な参考文 解できるように進んできたつもりです。 ですが , いったい何をやっているのかが理 違ったアプローチで成立したラジオシティ た。大域照光モデルから始まり , ひとあじ 2 回にわたってラジオシティを見てきまし 前回は原理と手順 , 今回は近似や改良と まとめと参考文献 もあるようです。 曲面であれば曲率方向に分割する方法など うな感じでしようか。ほかにも分割として , 方法です。影の形にパッチを切っておくよ 追跡して影となる部分を重点的に分割する いをうまく行うために , 光源からの光線を