あとじ 最初に評価される文 ( cgi. 「 b ) Fig. 1 要求を投げてから結果が返るまで HTTP サーバ 1 raise "PIease, use て ubyl. 5.4 or ねに er. ” if RUBY—VERSION く″ 1.5.4 ″ CGI スクリプト ( 環境変数 ) STDIN STDOUT メタ変数 ( 3 ) ボディ ( 4 ) ヘッダボティ ( 5 ) ist 定数の一部 2 183 : CR = ″薊 1 引 184 : IÆ = ” 012 ” 185 : EO も = CR 十 LF REVISION = '$ld: cgi. rb,v 1.23.2.8 2001 / 11 / 18 20 : 06 : 05 wakou Exp 引 186 : 187 : 188 : NEEDS—BINMODE = true if /WIN/ni. match(RUBY—PLATFORM) 189 : PATH—SEPARATOR = {'UNIX'=>'/' 'WINDOWS'=>'W' , 'MACINTOSH'=>' : り 190 : 191 : HTTP.-STATUS = { 192 : 209 : 210 : ) 211 : 212 : RFC822—DAYS = ⅳ [ Sun Mon Tue Thu F て土 Sat ] 213 : C822 ー HS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ] ( ログ ) STDERR ( 1 ) リクエスト送信 ( TCP ) ( 2 ) ⑦ ( 2 ) リクエスト受信 (TCP) ( 3 ) リクエストを解析 , CGI 起動 ( サーバ ) 園 ( 4 ) 結果の読みだし ( 環境変数とバイプ ) レスポンス リクエスト ( 5 ) 結果の書き出し ( バイプ ) ( 6 ) レスポンスの解析 ( サーバ ) ( 8 ) ( 7 ) レスポンスの送信 ( TCP ) H 幵 P 工ージェント ( 8 ) レスポンスの受信 ( TCP ) [ ※ ] mod ゴ uby の場合は別プロセスと限らない ・・ Ruby のバージョンチェック Ruby には宣言というものがないので , す るドキュメンテーションが充実していて R ( 177 行目 ) べての文は実行文です。 class の中も例外で D によるコメントの部分は 681 行あります。 はなく , この定数も require 時に評価され , なお , RD コメントの行数を数えるのには 177 行目で , require されたとき最初に評 代入されます。 価されるのは , List 1 に示す Ruby のバージ 次のワンライナを使いました ョンの検査です。 こで基準となる 1.5.4 は RFC822 DAYS と RFC822 MONTHS は % ruby -ne printif /A=begin/... /A=end/' 古い開発版です。リリース版の標準添付物 w で始まりますが , これは文字列の配列で cgi. rb は長いのですが , しかし , 相当に にバージョンチェックが必要かどうかは微 す。カッコの場合は対応するカッコで閉じ 節約された結果であることを本稿の後半で 妙ですね。 CVS で追いかけているときは , られます。文字列をいちいちクオートしな 解説します。 [ 注 1 ] ruby-l. 6.6 の場合。最長は net/imap. rb で くていいのでタイプ量が減るだけでなく , 必要となるかもしれません。 2364 行 ( RD コメントは 656 行 ) 179 行目では , 前回紹介した English. rb 読みやすくなります。 ・・冒頭のコメント ( 1 ~ 175 行目 ) を require しています。そして , これ以降は ・・入出力差し替え用プライベートメソ ファイルの最後までが class CGI … end の中 こではまずクレジットと利用例が書い ッド ( 215 ~ 227 行目 ) 身になっています。 てあります。この利用例を眺めればその機 環境変数と標準入出力が CGI 固有のイン 能を一覧できる仕掛けです。しかも , それ ト・・定数 ( 183 ~ 213 行目 ) タフェイスですが , これらは直接参照する だけでなく pstore を使った値の永続化の方 のではなく , cgi. rb 内で定義された専用の 全体で使用する定数が定義されています 法も例示されていてかなり親切です。 EXA (List 2 ) 。 CR, LF と EOL は改行文字です。 メソッドを経由して参照するようになって MPLE としてあげられているのは , EOL は end of line の略でしばしば見かける います (List 3 ) 。このようにしておくと , ・フォームの値の取得 サプクラスなどでこのメソッドを再定義す 略し方です。多義性を嫌って CRLF という ・フォームの値のハッシュとしての操作 ることによって , インタフェイスを変更す ・ファイルへの保存 名前をつける人もいます。 ることができます。標準出力として参照さ REVISION は RCS や CVS で checkin すると ・ファイルからの取り出し れる stdoutput は $DEFAULT—OUTPUT を きに自動的に設定されるもので , バージョ ・マルチパートの取り出し方 返しますが , これは EngIish. rb で定義され ンに対して一意な文字列を与える方法とし ・クッキーの操作法 ては広く使われる方法です。初期値として る $ くの別名です ( 前回夫叩 ) ・環境変数 $ ld $ と書いておくと , checkin するときに ・ H 幵 P ヘッダと HTML の出力方法 ・・ RD の見出し ( 229 ~ 231 行目 ) こうした文字列に自動的に展開されます。 です。最後の例では , このライプラリの大 cgi. rb に散りばめられている RD は , 基本 きな特徴である HTML 出力の支援機能が紹 NEEDS_BINMODE は File のモードとし 的には定義の前にその定義が提供する機能 介されています。 て binmode が必要かどうかを表すものです。 なあ Ruby を読もうじゃないか 1 1 5 = > ” 200 OK ″ "VARIANT—ALSO—VARIES" = 〉″ 506 variant A 0 Negotiates"
と猫のそれぞれを表すクラスとして , Huma n と Cat を , Mammal の公開派生クラスとし て定義します。 このとき , Human や Cat のインスタンス は ( " 一郎 " とか " タマ " といった個体として ) 生成されても , 不自然ではありません。 れは , " 人 " や " 猫 " が , 具体的な個体の存在 する具体的な概念だからです。また , " 歩 く " 行為は , 人や猫ごとに具体的に表現す ることができます。たとえば , 人は 2 本足 で歩き , 猫は 4 本足で歩く , という具合で す。つまり , Human::waIk ( ) と Cat::waIk ( ) には具体的な定義を与えることができるわ けです。 しかし , " 人 " や " 猫 " を一般化した概念で ある " ほ乳動物 " には具体的な個体 ( インス タンス ) は存在しませんし , " ほ乳動物 " の " 歩く " 行為を具体的に定義することもでき ません。つまり , 一般概念を表す MammaI のオプジェクトを生成するのはおかしいし , Mammal::walk() に定義を与えることも不 可能なのです。まとめると , 一般概念を表 すクラス ( すなわち抽象クラス ) は , 未定義 のメンバ関数 ( 純粋仮想関数 ) を本質的に持 っており , オプジェクトを生成することも / / 1 / / 2 / / 3 / / 4 / / 5 ・・コ ・解説 変換関数の定義方法と変換規則に関する 問題です。ほかのクラス Y から自クラス X へ の変換関数は , Y 型オプジェクト ( またはそ のリファレンス ) 1 個を引数として呼べるコ ンストラクタとして定義できます。逆に自 クラス X からほかのクラス Y への変換関数は , operator Y( ) { return Y 型オブジェクトー というメンバ関数として定義できます。返 却値型の指定はありませんが , Y 型オプジ ェクトを返さなければならないことに注意 してください (List 22 ) 。 こうしてユーザが定義した変換は暗黙の 変換としても利用されますが , 混乱を防止 するために , 2 回連続してユーザ定義変換 Li st 22 。 class A { int public ・ A( const int 土 = 0 ) : 土 ( 幻 0 int get—i( ) const { return } void set—i( int 土 ) { this->i = } 002 プログラミング 期末試験 8 では , / / 4 のコメントがついている , が行われることは禁止されています。 List ことを禁止するには , 該当するコンストラ ンストラクタを暗黙的な変換に用いられる explicit キーワードに関する問題です。コ ・解説 イ [ 問 13 」 ります。 B 型→ C 型 ) を要求しているのでエラーにな だけが 2 回連続したユーザ定義変換 ( A 型→ explicit X(const Y & y) { クタに explicit キーワードをつけて , できないというわけです。 ・解説 【 d ト・エ [ 問 11 」 て読み直してください。 になっているので , 空欄に正解を当てはめ に関する問題です。問題文がそのまま解説 C + + で新たに導入されたキャスト演算子 [ 問 12 」 class B ( int public ・ 加セ get-i( ) const { return } B( 00n int = 0 ) : 土 ( 幻 { } A a = B b = 1. C c = c 土 n セ main( ) { 00n8 ヒ C h( 00n8 に C & c ) { return c; ) cong し B g( cons し B & b ) { return b; cons セ A f( const A & a ) { return c( const B b ) : i(). get—i()) { } C( 00 れ st int 土 = 0 ) : 土 ( 土 ) 0 public ・ class C { operator A( ) { return A ( 土 } B( co れ st A a ) A al; B bl; C 0 c1 = bl = al; return 0 ー f( 6 g( 7.0 h( h( A( 5 ) h( g( A( 4 ) ) h( B( 3 ) g( A( 2 ) f( B( 1 ) / / A から自クラス B への変換 / / 自クラス B から A への変換 特集 2 C ℃ + + / Java 実力チェックプログラミング期末試験 69
nt_init を持っています。このメソッドは ev al でメソッドを実際に定義します。メソッ ドは形式に合わせて 3 つのパターンに分類 されていますが , これらのパターンは HT ML の種類に依存しないのでここでは定義 されません。 1908 行目の HtmlExtension モジュールは 前の行で定義された要素メソッドのコール バックを定義します。これらのコールバッ クによってメソッドごとに異なる引数の処 理が定義されます。 ・・ HTML ごとのモジュール ( 1719T763 行目 ) Htm13 , Htm14 , Htm14Tr , Htm14Fr は H TML の差異を表現するためのモジュール で , いずれも d 。 ctype と要素メソッドを定 義しています。 List15 に抜粋します。 形式的には HTML は SGML アプリケーシ ョンなので DOCTYPE という識別子が要求 されます。これをメソッドとして定義した のが doc pe です ( 1721 ~ 1723 行目 ) 。単に 決まった文字列を返すだけです。 1725 ~ 1761 行目は要素メソッドを定義す るためのメソッドです。まず TagMaker モ 同様に Htm14 , Htm14Tr , Htm14Fr も eleme 759 : end d した Htm13 モジュールで定義されています。 1907 行目の element_init は則の行で exten 呼ぶことにします。 れています。これらを以下では Htm13 系と しては Htm14 , Htm14Tr, Htm14Fr が用意さ り替えられる部分です。ほかの HTML に対 こだけが initialize の引数 pe で切 です。 固有の要素メソッドを定義するためのもの 1906 行目の Htm13 モジュールは HTM ロ .2 t 14 ) 。 って組み込むモジュールを決定します ( Lis TML の種類を指定します。この種類に従 先ほど見たように CGI : : new の引数には H ・・ initialize(1891 ~ 1925 行目 ) にコードを見ていくことにしましよう。 理解するために , 以下では実行される順番 やや混み入ったこの定義のシーケンスを す。 に雛形の雛形まで用意し 2 段階で生成しま は共通する部分がたくさんあるので , さら 生成するというものです。ただし , 雛形に るモジュールを extend したうえで , eval で ェクトを生成するときに in ⅲ alize で該当す ジュールとして用意しておき , CGI オプジ の HTML に対応するメソッド群の雛形をモ cgi. rb で採用している方法は , それぞれ onal には 65 個の要素があります。 ML 4.0 Strict には 55 個 , HTML 4.0 Transiti るのはたいへんなことです。たとえば HT 数の要素があるので , これをうまく表現す なります。それぞれの HTML にけっこうな って用意するかということが 1 つの問題に L の種類に合わせた要素メソッドをどうや ジュールを extend するところからこのメソ ッドは始まります。次の節で見るように T agMaker モジュールはパターンごとに nn element def, nOE element def , nO ele ment_def という 3 つのメソッドを定義して いて , これらは実際にタグを作るためのコ ード片を文字列として返すメソッドです。 List 15 では {nn_element—def を呼ぶ部分を 抜き出しています ( 残りのパターンは 1741 ~ 1759 行にあります ) 。 element_init は要素ごとに def 文を文字列 として作って , 最後に eval するだけですが , def 文を作るところでヒアドキュメントが利 用されています。さらに , ヒアドキュメン トで挟まれる定義の中身の部分は TagMak er モジュールのメソッドで作られます ・・ TagMaker モジュール ( 995 ~ 1053 行目 ) このモジュールは Htm13 系のモジュール に extend するためのものです。タグのパタ ーンに応じて要素名からタグの生成に使わ れるメソッドのコードを 3 パターンぶん定 義しています。タグのパターンは DTD 注 2] での要素宣言におけるタグ省略の可否と宣 0 List 747 : 748 : 749 : 750 : 751 : 752 : 753 : 754 : 755 : 756 : 757 : 758 : メタ変数をアクセスするためのメソッド 746 : fo て env in "'[ AUTH-TYPE CONTENT-TYPE GATEWAY—INTERFACE PATH—INFO PATH_TRANSLATED QUERY—STRING REMOTE. _ADDR REMOTE_HOST REMOTE—IDENT REMTE—USER REQUEST—METHOD SCRIPT—NAME SERVER—NAME SERVER—PROT(Æ)L SERVER_. SOFTWARE HTTP—ACCEPT HTTP—ACCEPT-CHARSET HTTP-ACCEPT_ENCODING HTTP—ACCEPT—LANGUAGE HTTP—CACHE—CONTROL HTTP—FROM HTTP—HOST HTTP_NEGOTIATE HTTP—PRAGMA HTTP_REFERER HTP_USER_AGENT ] eval ( くく -END ) def #{env. sub(/AHTTP-/n, env-table["#{env)"] を ) . downcase) end END List 623 624 625 626 627 628 629 637 649 650 デレゲーションを使っている Cookie require "delegate" c lass Cookie く Simp 厄 D 引 egator def initia lize ( name = , *value) options = if name. kind—of?(string) { = > name, "valuen else @value = Array(options["vaIue"J ) super(@value) => value ) List メソッドによる HTML の表現 # ! ん sr/local/bin/ruby require "cgi" cgi = CEI: : れ e ” ht 4 ” ) # add 日 T generation methods cgi ・ ou 日 ) d0 CGI: :pretty cgi. html{ cgi. head{ cgi. 缸目eドtit尾つ ) 十 cgi ・ body{ cgi. hl { "under construction") 十 cgi . p{ SO てて y , no に avail ab 厄 . cgi ・ a("href" = > ″ end 1 1 8 C MAGAZINE 2002 3
(void * ) を呼び出すことになります。 [ 問 8 」 ア ・解説 68 C MAGAZINE 2002 3 ジェクトがあればそのデストラクタを呼ぽ よれば , A: : ~ A ( ) は A の基底クラスサブオプ 前述したデストラクタの呼び出し規則に ( ) が呼ばれるわけです。 こでは A : : ~ A 関数が呼ばれます。つまり , トの型には関係なく , A で定義されている 関数なら叩が指している実際のオプジェク 叩を介して呼ばれるメンバ関数が非仮想 ラクタが呼ばれます。 という文を実行すると , 叩を介してデスト de lete ap; さて , 問題となっている , いう順番で呼ばれることになります。 には , デストラクタは B::-B() → A::-A() と 規則に従えば , B 型オプジェクトの破壊時 てオプジェクト全体が破壊されます。この クトを破壊します。これを再帰的に適用し トラクタを呼び出して各基底サブオプジェ 順とは逆順に ) すべての基底クラスのデス 壊します。その後 , ( 基底として指定した して各データメンバサブオプジェクトを破 ラクタをメンバの宣言順とは逆順に呼び出 部分を破壊した後 , データメンバのデスト デストラクタは , 最初に自クラスの独自 行われるかを復習しましよう。 トラクタの呼び出しがどのように連鎖的に クタが非仮想関数だからです。まず , デス デストラクタが呼ばれないのは , デストラ List 7 の main 関数内の、 delete 叩 ; ' で B の の派生クラスの関数の名前は基底クラスの 非仮想関数の名前を " 隠し " ます。ですか ら , 3 つの B::f() が A::f(char*) を隠してし まうために , b. f ( & c ) ; の呼び出しは , 引数 型が一致する A::f(char*) を見つけられず , char* から void * への変換が行われて B : : f 【 b ト・オ うとしますが , A の基底クラスは存在しな いので , デストラクタの呼び出しの連鎖は A::-A ( ) が最後ということになり , 呼び出し はそこで終了してしまいます。つまり , B : : B ~ ( ) が呼ばれる機会は失われてしまう のです。しかし , デストラクタを仮想関数 にすれば , 叩の指している実際の型に従っ てデストラクタが呼ばれることになります。 つまり , 、 delete 叩 ; ' で最初に B : : ~ B ( ) が呼 ばれ , 次いで A : : ~ A ( ) が呼ばれてオプジェク ト * 叩全体がきちんと破壊されることにな ります。このように , デストラクタを仮想 関数にするのは定石なので覚えておいてく いる " なので , has-a 関係を表しています。 ですから , Airplane クラスに static でない Engine 型データメンバを定義することにな ります。 実は , has-a 関係は , private または protect ed な派生を使っても表現できないことはあ りません。たとえば , 甲 lane クラスを Eng ine クラスの private ( または protected) な派 生クラスとすると , AirpIane 型オプジェク トの中に基底クラスオプジェクトとして En gine 型サブオプジェクトを " 持つ " ことがで きるわけです。しかしこの場合 , AirpIane 型オプジェクトは Engine 型オプジェクトを ださい。 第 9 」 ・解説 ①・・・イ②・・・ク ③・・・コ クラス階層の設計に関する問題です。通 常 , クラスは対応する何かしらの概念を表 しています。 たとえば , 'Document クラスは「書類」と いう概念を表している " という具合です。概 念間の関係には大きく分けて " is - a 関係 " と 、 has-a 関係 " があります。 前者は " 概念 A は概念 B の一種である " という関係で , クラス間の関係としてこれ を表現するにはクラス A をクラス B の公開派 生クラスとして定義することになります。 後者は。、概念 A は概念 B を持っている " と いう関係で , これをクラス間の関係で表す には , B 型データメンバ ( もしくは B 型オプ ジェクトへのポインタかリファレンス ) を クラス A に持たせるように定義します。 ①は , " 「グラフィック書類」は「書類」の 一種 " なので , is - a 関係を表しています。す なわち , Gr 叩 hicaIDocument クラスを Docu ment クラスの公開派生クラスとして定義す ることになります。 ②は , " 「飛行機」は「エンジン」を持って 1 つしか持っことができません。飛行機に は 2 つのエンジンを搭載することもあるで しようから , 継承を使った has - a の表現は採 用できないことになります。 こういった理由や , わかりやすさの点か ら , has - a 関係を表現する際には , メンバと して持つ方法 ( 「包含」という ) が推奨されて います。 ③は , 合成概念に関する問題です。℃は A の一種 " かっ " C は B の一種 " なので , C は A と B の合成概念ということになります。 の場合 , 2 重の is - a 関係を表すために , 多重 継承を使って , C を A と B の公開派生クラス として定義することになります。 【 d ト・サ ・解説 【 e 】 純粋仮想関数と抽象クラスに関する問題 です。 抽象クラスは , C + + では一般概念を表現 するために導入されました。たとえば , " ほ 乳動物 " を表すクラス Mammal を定義した とします。この Mamma には " 歩く " 行為を 表すメンバ関数 walk ( ) を定義しておきまし よう。そして , ほ乳動物の一種である人間
メ五ロ ス - = ロ第八十七語 万プロセスの同期と 千 きだあきら いであり , 「 x + 1 」のように一般の式を指定 非同期メッセージ通信 できる。一方 , receive 文の引数は , そこに キーワード proc を用いて定義した SR 言語 値を受け取るための入力パラメータであっ のプロセスを呼び出すには , 2 つの呼び出 て , 事前に宣言しておいた変数を指定する しモードがあった。 call による同期プロセ 必要がある。 ス呼び出しと , send による非同期プロセス 実は , send の構文は非同期プロセス呼び 呼び出しである。 出しとまったく同じで , send による呼び出 復習しておくと , ca Ⅱを用いた同期呼び し側のコードを見ただけでは , それが非同 出しでは , 呼び出しが行われた時点で新し 期メッセージ送信なのか , 非同期プロセス いプロセスが生成され , それが終了するま 呼び出しなのかを区別できない。両者は , では呼び出し側のプロセスはプロックされ 受け取り側 ( 呼び出される側 ) が receive 文な る。これに対して send を用いた非同期呼 のか , proc 定義されたプロセスなのかによ び出しでは , 呼び出しによって新しいプロ って変わるのだ。 セスが生成されるのは同じだが , 呼び出し なお , 非同期メッセージの引数はゼロ個 側のプロセスはプロックされず , 両方のプ でもよい。その場合 , 「 sendmes() 」と「 rec eivemes ( ) 」といった構文になる。引数のな ロセスは並行に実行されるのであった。 これら 2 つの呼び出しモードは , いずれ い非同期メッセージの送受信は , セマフォ も呼び出しが行われるまでは呼び出される に対する v , P の操作と等価である。という 側のプロセスは存在せず , 呼び出し側のプ か , SR の流儀では非同期メッセージ通信の ロセスだけが起動している。しかし , プロ ほうがプリミテイプであり , セマフォに対 グラミングの都合から「並行に実行を続け する V , P 操作は非同期メッセージ通信を用 ている。 ている 2 つ ( 複数 ) のプロセスの間で情報を List 1 では , 最初に f00 が bar に mesl を送 いて実装しているという解釈になっている。 やりとりしたい」という要求もある。これ 信し , それを受信した bar は逆に fo 。に mes2 クライアント / サーバ間通信 を実現するための 1 つの方法として , SR に を送信する。そして f00 が mes2 を受信した は非同期メッセージ通信 (Asynchronous M 時点でプログラムの処理が終わる。 send で 非同期メッセージ通信を用いるより現実 essage Passing) が用意されている。 メッセージを送信する側は , 叩宣言で定義 的な例として , クライアント / サーバモデル における通信が考えられる。このモデルで したとおりの個数と型で実引数を渡す。 非同期メッセージの構文 の場合 , 実引数は手続き呼び出しと同じ扱 は , クライアントとサーノヾは独立したプロ SR では , 非同期メッセージの送信には ( 既出の ) send 文を用い , 受信には receive 文を用いる。ちなみに , 非同期メッセージ はキュー (queue) によって管理される。連 続してメッセージを送ると , 新しいメッセ ージはキューの末尾に追加される。一方 , メッセージを読み出す側では , 最初に送信 されたメッセージから順次受信することが 保証される。 List1 は , 非同期メッセージ送受信の原 理を示すプログラムである。まず叩によっ てメッセージに該当するオペレータを定義 する。 こでは mesl , mes2 という 2 つのオ ペレータを定義している。また , f00 , bar という 2 つのプロセスがあり , メッセージ を相互に非同期に送受信し合う構造になっ 1 58 C MAGMINE 2002 3 i st # ー土 s し 1. sr # 非同期メッセージ通信のスケルトン resource listl ( ) OP mesl(): 土 n y: b00 嵭 z: int) OP mes2(): b00 嵭 y: 土 n 2 : int) process f00 var X : 土 n し = 1 , sw : 20 し y: int sendmesl(x 十 2 , true, y 十 8 ) receive mes2(SW, X, y) write("foo", sw, x, y) end f00 process bar var w: 土 n flag: b00 し z: int receive mesl(), flag, z) write( ” ba て” , Ⅳ , flag, 幻 sendmes2(fIag, w- 1 , z ー 4 ) end bar end # オペレータ定義 # オペレータ定義 # 非同期メッセージ送信 # 非同期メッセージ受信 # 非同期メッセージ受信 # 非同期メッセージ送信
Ruby? ーを共有する際に現状に合わないからエス す。 List11 で作られるメソッドはいずれも ッドを使うようにしていれば , 必要なとき にこれを再定義することで , CGI スクリプ ケープを抑止する機能が要求されたのがき 動的に決定しなくてもよいものばかりです こだけで 26 個のメソッドが定義され トを変更することなくバッファリングの処 っかけです。 が to s は CGI : : esc 叩 e でエスケープした値を ています。もしそれぞれをまわりと同じス 理などを自分で行うことができます。 文字 " & " で連結します。 CGI::escape は List タイルで普通に定義したのなら , 1 つのメ ・・クッキー ( 595 ~ 711 行目 ) ソッド当たり 4 行 ( 定義 3 行 + 空行 1 行 ) になり 5 に示したとおりですが , そこではエスケ ープする対象が固定されています。 CGI::C ますから , 全部で 100 行を超えてしまいま この部分ではクッキークラス CGI::Cooki e が定義されています。 cgi. rb では CGI#coo ookie::parse ではちょうどこれの逆となり す。行が増えるだけでなく , 同じ訂正を加 kie で参照することができ , その値はハッ ます。こういったことは厳密にいえば標準 えようとすると 26 か所同じことをしないと いけないのでたいへんそうです。 シュと同じようにして得られます。この C 化されているわけでなく , あくまでデファ こういう理由がこのような eval を使った GI : : Cookie は明示的なデレゲーションを使 クトスタンダード程度の意味合いしか持ち メソッド定義の背景にあると思うのですが , っていることを除けば , このコードはヘッ ません。 一方で可読性を多少下げることになります ダと似ている部分も多く , とくに変わった すでに見たように header メソッドでは生 また D00 Th000 さんの RDoc のようなに ところはありません。デレゲーションとは , のヘッダを設定することもできるので「 CG I : : Cookie を使わなくてもよいではないか」 継承することなく機能を他のクラスのオプ キュメント自動生成器の恩恵を受けること という考え方もあります。一方で , 「そうい ジェクトに任せるデザインパターンです。 ができません。 HTPP のようにキーワード った生々しい部分は少なくとも CGI スクリ の多いプロトコルの実現などではこういっ CGI::Cookie は配列のようなインタフェイ プトからは隠したい」とか「 CGI : : Cookie が たことになりがちで , なかなか頭の痛い問 スを持ちます。しかし , クッキーは Array とても便利だ」という人にとってはこうい 題ではあります。 と is-a 関係にしてもあまりうれしいことは ありません。このような場合にデレゲーシ った部分がカスタマイズできればたしかに ・・ HTML の要素メソッド ョンを使います。 Ruby では delegete. rb とい 便利でしよう。 この議論は本稿の執筆時点では決着がつ HTML の要素メソッドは cgi. rb の独自性 うライプラリで , 短く書くことができます。 が発揮される機能の 1 つです。 HTML の要 いていないようですが , ライプラリに要求 デレゲーションに関係する部分だけを List 素をメソッドで表現したものです。 HTML されるのは何かということを考えさせてく 10 に抜き出しました。 SimpleDelegator のサ は入れ子構造になっていますが , たとえば れる議論でした。 プクラスにして , initialize でデレゲートし List 12 のように , これをプロックで表現す てもらう @value というハッシュを引数とし ・・ QueryExtension(736—948 行目 ) ることができます田 st 13 は出力結果 ) 。属 て super(@super) を呼んでいます。 性は引数として与えます。 CGI::new の引数 QueryExtension モジュールは CGI に対す このオプジェクトの最大の機能は HITP は HTML の種類を表すものです。指定でき る入力のインタフェイスを実現します。つ ヘッダの値として有効な文字列に変換する ためのメソッド to ー s と , 逆に HITP ヘッダ まり , リクエストのヘッダとボディを解析 るのは , してメソッドとして参照できるようにしま ” htm13 ” (HTML 3.2 Final) の値として与えられた文字列を CGI : : Cooki す。マルチパートにも対応しています。 ” htm14 ” (HTML 4.01 Strinct) e オプジェクトに変換するためのクラスメ ” htm14Tr ” (HTML 4.01 Transitional) ソッド parse です。これは「適切」にエンコ のモジュールは CGI オプジェクトに機能を ” htm14Fr ” (HTML 4.01 Frameset) 追加するためのクラスで in ⅲ alize において ーディングします。 の 4 種類です。また , この例のように CGI:: ところで去年の暮れに ruby - list で , CGI:: extend されます。 pre 町を使えば , ネストの深さに合わせて この QueryExtension ではメタ変数をメソ Cookie はエスケープをどうするべきかとい 出力する HTML に対してインデントを加え ッドとして提供するために , 多くのメソッ うことが議論されました。 CGI::Cookie は ドがロード時に定義されます。これは主に あまりにも行儀よくふるまうので , 既存の ます。 このような機能を実現する際には , HTM ものを含む複数の CGI スクリプトでクッキ 保守性を高めることを狙っているようで List List 残ったキーの扱い option の検査と削除をいっぺんに行う 8 9 if options. has—key?("connection") 451 : buf 十 = "connection: ”十 options. delete("connection") 十 EOL 452 : 453 : end ・叩に土0nS. each{lkey, valuel 489. buf 十 = key 十” 490 : 491 : ) 十 value 十 nL 1 1 / なあ Ruby を読もうじゃないか
[ 問 8 」 List7 を実行すると main 関数内の , delete ap, で ap に指されている B 型オブジェクトを解放している処理で , B のテストラクタが呼ばれないという問題が観測できる。この問 題を解決するにはどうしたらよいか。選択肢 ( ア ) ~ ( 工 ) の中か ら正しい解決策を選択せよ。 選択肢 List ( 工 )B - B ( ) をインライン関数にする ( ウ )B -B() を static な関数にする ( イ )B - B ( ) を仮想関数にする ( ア ) A. -A() を仮想関数にする p は 0 ・ 0 ね 88 A ( using namespace std; #include く土 08 い eam> [ 問 9 」 return 0 ー delete ap; A * ap = new B; int main()( -B() ( co Ⅱセくく新 ~ B ( 尸くく end 嵭 } B(){ cout くく ( 尸“ end 嵭 } public ・ cl 8 B : p は 0 A { -A(){ cout くく第 ~ A ( 尸くく end 嵭 ) A(){ cout “” A ( 尸“ end 嵭 } ( 4 点 ) 002 プログラミング 期末試験 選択肢 ( ア ) class GraphicaIDocument . private Document { ( イ )class GraphicalDocument : public Document { ( ウ )class GraphicalDocument : protected Document { Document doc, ( 工 ) class GraphicalDocument { ( 5 点 ) ( 5 点 ) を定義する ( ク ) クラス Airplane に static でない Engine 型テータメンバ スとして定義する ( キ ) クラス Airplane をクラス Engine の protected な派生クラ として定義する ( カ ) クラス Airplane をクラス Engine の public な派生クラス として定義する ( オ ) クラス Airplane をクラス Engine の pr ⅳ a な派生クラス 選択肢 下の選択肢 ( オ ) ~ ( ク ) の中のどれがもっとも適正か答えよ。 ラスを Engine とすると , AirpIane クラスの設計としては , 以 ムを作成したい。飛行機のクラスを Airp ぬ ne , 工ンジンのク ②一般的な飛行機の飛行シミュレーションを実行するプログラ クラスの設計の指針に関して , 以下の各問に答えよ。 ①一般的な書類を表す Document クラスと , 特殊な書類である グラフィック書類を表す GraphicalDocument クラスがある。 このとき , GraphicalDocument クラスの設計として適正なも のを以下の選択肢 ( ア ) ~ ( 工 ) の中から選択せよ。 特集 2 C ℃ + + / Java 実力チェックプログラミング期末試験 61
・解説 main の中の関数呼び出しにびつくりした 読者もいるでしよう。こうした表現も ANSI C では可能になっています。荒唐無稽な , 問題のための問題と思われたかもしれませ ん。たしかにこのような形式の呼び出しが 直接登場するケースは一般的ではないでし よう。けれども , 類似のデータ構造を扱う ことは , システムプログラムなどでは , 決 して皆無ではないといえます。 この問題は , m ⅲ n の中の myF 。。の初期化 から , f00 のメンバ bar は ( 少なくとも ) 要素 3 個の配列であることがわかります。そし て , そこに初期化子として記されているの は myBar です。そこから型を拾えばよいの で , 実は簡単な問題なのです。 [ 問 19 」 第 1 の解 . void ( *t)(void) = hello, ( *hello)(void) = world, ( *world)(void) 第 18 」 (char * 第 2 の解 . #define world() (hello)() #define e Ⅱ 0 ( ) (world)() を使うことです。第 1 の解のようにすれば , それを行う第 1 の方法は , 関数ポインタ 関数 w 。 rld の定義を交換してやります。 と出力されるので , 何とかして関数 he Ⅱ o と he Ⅱ 0 world をそのままコンパイルすると , 投稿を参考に再構成したものです。 List 17 この問題は , 読者の久保則幸さんからの ・解説 ローカルに hello と world という関数ポイン タ ( 両者の型は「 void ( * ) (void) 」 ) を宣言す ると同時に , ローカルの he Ⅱ 0 はグローバル な関数 world を指し , ローカルの world はグ ローバルな関数 he Ⅱ o を指すという状態を作 り出すことができます。 ANSIC では関数ポ インタを用いて関数を呼び出す場合にも , 「 he Ⅱ 0 ( ) ; 」と書くだけでよいので , 「 hello 」 が関数名なのか , 関数へのポインタ変数名 なのかは見分けがつきません。そこがこの 解のミソです。 第 2 の解は , マクロ定義を使います。ポ インタ変数を持ち込むことなく , ソースの 字面上で入れ替えてしまう方法です。 しかし , 単純に #define t he Ⅱ 0 #define he Ⅱ 0 world #define world t のようなマクロ定義をしてもうまくいきま せん。その理由は , こでは詳しく説明し ませんが , このような単純なマクロで 2 つ の文字列を交換することはできないのです。 しかし , 今回のケースでは関数呼び出しで あることに注目すると , 第 2 の解のような 定義を用いれば交換することができます。 ANSI のプリプロセッサの仕様では , マク ロ定義にはオプジェクト形式マクロと関数 形式マクロの 2 種類があります。関数形式 マクロでは , マクロ名の後ろに , ( 空白や 改行だけを挟んで ) マクロ引数リストのた めのカッコがきているときだけマクロ呼び 出しと解釈されます。そのため , 展開後が 「 (world) () 」といった形式であると , world という名の関数形式マクロの呼び出しとは 解釈されません。 解答は , List19 のとおりです。 ・解説 データを交換する swap というマクロは , 002 プログラミング 期末試験 dO { て uct 2 ( 0 vtgizeof(x) *(gtruct z*)&(y) = セ洋 ) while ( / * CONSTCOND * / 0 ) 通常は int の変数の交換だけとか , double の 変数の交換だけしかできないようなマクロ として定義することが多いでしよう。 しかし , List19 のようなマクロではⅲ t や d ouble などの組み込み型はもちろん , 構造体 でも配列でも , 両者が単項の「 & 」を適用可 能なオプジェクトで , そのサイズが同じで ある限りは交換可能になります。 こでのポイントは 2 つあります。 1 つは 構造体ならば任意のサイズのオプジェクト を代入 ( 実体はメモリのプロック転送 ) でき ここに示した解が ることです。もちろん , 唯一というわけではなく , malloc して memc py して斤 ee するという方法もありえるでし よう。しかし構造体を使うほうが ( まだ ) 簡 単です。 もう 1 つのポイントは , 全体を d 引・ヨ whi le ( 0 ) で囲むことです。数ステップの文を含 むコードをマクロ化し , 一見関数であるか のように呼び出す際には , こうしておくと , あたかも関数と同じようにマクロ呼び出し の後ろにセミコロンを打って利用できるの で便利です。 なお , List 19 の最終行の / * CONSTCO ND * / というコメントは , lint というプロ グラムのためのもので , コードの動作上は 意味はありません。 このような恐ろしげなマクロを見たこと がない方は , まったく非現実的な例である と非難したくなるかもしれませんが , 少な くとも FreeBSD や NetBSD といった BSD 系 の OS のヘッダファイルでは , この程度に複 雑なマクロは決してめずらしいものではな List いことを付記しておきます。 特集 2 C/C + + /Java 実力チェックプログラミング期末試験 5 /
あをじ List List 1 2 の出力結果 Content-Type : text/html Content-Length: 318 く !ImTYPE ー PUBLIC "-//W3C//IYIlD 4.01 / / ″ ”httP://げ調謝3.org/TR/htm14/strict.dtd"> <HEAD> <TITLE> title </TITLE> <BODY> く HI 〉 sorry, no セ available. <A href= ( 叩 ) く / わ CGI の initialize query") 1891 : def initialize(type ま 1904 : case type when ”れ tm 日” 1905 : 1906 : extend Htm13 引 ement—init ( ) 1907 : extend HtmlEXtension 1908 : when ” h に 4 ” 1909 : end 1923 : 1924 1925 : end く /HEAD> under construction List HTML 4 ℃における要素宣言の例 - anchor く / く /BODY> <!ELEMENT A ー く / 日 T > List HtmlExtension モジュール ist Htm13 モジュール 5 1719 : Htm13 1720 : def doctype 1721 : %I<!DOCTYPE HTML PUBLIC n-//W3C//DTD HTML 3.2 Final//EN">l 1722 : 1723 : end 1724 : 1725 : 1726 : 1727 : 1728 : 1729 : 1733 : 1734 : 1735 : 1736 : 1737 : 1738 : 1739 : end eval (methods) 1760 : 1761 : end 1762 : 1763 : end # Htm13 1056 : e Html Extension ( による説明 ) def a(href = ”” ) attributes = if href. kind—of? ( string ) ( 新 EF ” href ) e lse href end if ock—given? super(attributes){ yield ) super ( attributes ) end end ( 要素の定義が続く ) end # HtmlExtension 1716 : 1064 : 1065 : 1066 : 1067 : 1068 : 1069 : 1070 : 1071 : 1072 : 1073 : 1074 : 1075 : def e lement—init extend TagMaker methods = for element in 宅ⅵ A 質 I B U STRIKE # # # 省略 CAPTION ] methods 十 = <<-BEGIN 十 nn—element-def(element) 十“ - 風 def #{element.downcase}(attributes = { ) ) BEGIN 3. TagMaker が値を生成するためのコー 17 ) 。 言済み内容をヒントにしています。たとえ 引数を処理した後は , super を呼ぶこと ばリンクなどで使われる A 要素は , 開始タ ドを作る で Htm13 系モジュールで定義されたメソッ そのために多少ややこしくなってはいま グも終了タグも省略することができません。 すが , コード全体の構成としては見通しの ドに任せます ( 1064 ~ 1075 行目 ) 。 super を これは HTML の DTD では List 16 のように表 よいものとなっているうえに , TagMaker されます。 A に続く 2 つのハイフンが開始と 決定しているのは in ⅲ alize における extend と Htm13 系を使った 2 段階のテンプレート 終了の両方が省略不可であることを表して の順番です。 でコードの圧縮が実現されています。 このモジュールは API を提供するので RD います ただ cgi. rb にも問題がないわけではあり による説明がついています。これに対して , TagMaker モジュールでは こういったノヾ ません。苦労して定義されている要素メソ ターンをもとにヒントにメソッドを用意し Htm13 と TagMaker は実装のためのモジュー ッドですが , 入れ子の正しさまではチェッ ているのです。これらのメソッドはコード ルであってユーザに提供するためのもので クしてくれません。たとえば , A 要素の中 片を返し , Htm13 系モジュールのメソッド はないので説明がついていません。 に P 要素を置くのは HTML 的に間違いです 内で展開されます。 まとめ [ 注 2 ] Document Type Definition : SGML の文 が , これを指摘してくれるわけではないの 書型定義 です。また , プロックは文字列を返さなけ HTML の要素メソッドについてまとめる ・ HtmlExtension モジュール ればならないので , 要素を + などで連結す と , 次のようになります。 0056 ~ 1716 行目 ) 1 . Htm 旧 xtension がインタフェイスを与 る必要があり , Emacs を使う人には ruby- mode. el のインデントとちょっと相性がよ このモジュールは要素メソッドの引数処 える 2. Htm 旧系が実装を分類して定義する 理を請け負う部分を実装しています ( List くありません。 0 なあ Ruby を読もうじゃないか 1 1 9
[ 問 12 」 【 b 】 【 e 】 【 f 】 【 k 】 い】 ・解説 ・・ 10 , 40 ・・ 30 ・・ 40 40 40 40 ハイドされたフィールドのアクセスと , オーバライドされたメソッド呼び出しの確 認です。 List 5 では , Base , Midsub , Subsub とい う 3 つのクラスが直線的なクラス階層を構 成しています。そして , それぞれのクラス の中でインスタンス変数として x と y が宣言 され , その結果 , 上位クラスの同名のイン スタンス変数をハイドしています。 まず , Base 型の変数である il , i2 を通じ て行うアクセスを考えてみましよう。 il. x とか i2. x といった形でフィールドをアクセ スする場合 , il, i2 の静的な型 ( つまり変数 宣言時の型 ) に基づいてアクセスするフィ ールドの実体がコンパイル時に決定されま す。この場合 , いずれもクラス Base の x に なります。したがって , 【 a 】と【 d 】はいず れも 10 になります。 一方 , il. getY() や i2. getY() といったメソ ッド呼び出しは , il , i2 の動的な型 , すな わち , その時点で il , i2 が保持していたオ プジェクトの型に応じて動的にディスパッ チされます。ただし , getY メソッドはクラ ス Subsub では定義されていないため , il , i2 ともクラス Midsub の getY メソッドが起動さ れます。 84 C MAGAZINE 2 2 3 このとき , クラス Subsub のインスタンス を保持している i2 を通して getY を起動した 場合でも , getY はクラス Midsub で定義され たメソッドである以上 , それが返す y の値 はクラス Midsub のインスタンス変数 y の値 です。この結果 , 【 b 】と【 e 】はどちらも 40 になります。 il. getXY() や i2. getXY() というメソッド 呼び出しも , 同様に動的ディスパッチが行 われます。この場合も , やはり呼び出され るのはクラス Midsub で定義された getXY で す。 ただし , クラス Midsub の getXY メソッド は , 内部で再び ge Ⅸと getY を呼び出してい る点に注意が必要です。 il. ge Ⅸ ( ) の中か ら呼び出した場合 , il の動的な型は Midsub なので , ge Ⅸはクラス Base から継承したも のを呼び出し , getY はクラス Midsub で定義 したものを呼び出します。 結果として , ge Ⅸ V からは " 10 , 40 " が返 されます ( 【 c 】 ) 。一方 , i2. ge Ⅸ Y ( ) の中か ら呼び出した場合 , i2 の動的な型は Subsub なので , getX はクラス Subsub で定義したも のを呼び出し , getY はクラス Midsub から継 承したものを呼び出します。この結果 , get XY からは " 70 , 40 " が返ります ( 【 f )) 。 次に Midsub 型の変数である jl と Subsub 型の変数である j2 を通して行う後半部分を 見ていきましよう。実は前半部分と違うの は , jl. x および j2. x という , フィールド x のア クセス結果だけです。前述のとおり , フィ ールドアクセスは変数の静的な型に応じて 行われるので , Midsub の x を参照する【 g 】 は 30 , subsub の x を参照する【 j 】は 70 とな ります。 残りは前半の対応する部分の解答とまっ たく同じです。 [ 問 13 」 【 a 】・・・ f. x : 12 【 b 】・・・ f. y : 34 ・解説 s ねⅱ c 変数のアクセスに関する確認です。 s ねⅱ c 変数は別名「クラス変数」と呼ばれる ように , インスタンスごとに生成されるの ではなく , あるクラスに対して 1 つだけ実 体が存在します。そのため , 通常はクラス 名に対してフィールド名を修飾してアクセ スするのですが ( F00. x のように ) , Java の文 法上は , 該当クラス型の変数に修飾してア クセスしてもかまわないことになっていま す。しかも , その場合 , 実際のオプジェク トを参照することはないため , その変数の 値 ( オプジェクトへの参照 ) は , null でも問 題ありません。 したがって List6 ではとくに例外が発生す ることもなく正常に終了します。ただし , static フィールドの x と y は , それぞれ変数の 初期化子とインスタンス初期化子のコード によって値が与えられますが , z には値が与 えられません。 List 6 では z を初期化してい るように見えるコードはありますが , これ はインスタンス初期化子コードなので , ク ラス Foo のインスタンスが生成されない限 り実行されないのです。その結果 , z はデ フォルト値である 0 が設定されたままとな ります。 [ 問 14 」 Fig. IO のとおりです。 ・解説 例外の捕捉と再投入 , および ~ 血 al , そして別スレッドで捕捉されなかった例外 の処理といった , さまざまな概念の総合的 な確認です。 まず , List 7 の ( コメントを外す前の ) 動 作を追ってみましよう。クラス Tg 印のメソ ッド main の中から , クラス Bar のインスタ ンスを生成し , それを t に格納します。