インタフェイス - みる会図書館


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

1. 月刊 C MAGAZINE 1992年6月号

0 として表現されます。本稿て、は , ・コンポーネント ( 構成要素 ) ・インタフェイス と呼ぶことにします。 Fig. 1 オプジェクトレンズコーティング規約 ・概要 オプジェクトレンズ ( ObjectLens ) は , C 言語を使って , オプジェクト指向風のコーティングをする 手法である。マクロ定義ファイル object. h と基本関数ファイル object. c が提供される。 ・オプジェクト オプジェクトは構造体とそれを扱う関数のセットて表現する。オプジェクトの宣言はそのオプジェ クト名がついたヘッタファイルで行う。ヘッダファイルは 2 回 include されても大丈夫なように # ifndef オプジェクト名 H … #endifC くくる。その内部 Cobject. h を include する。構造体を使用しない単 純なオプジェクトの場合には typedef を使用する。「 ank. h を参照のこと。 ■オプジェクトのコンポーネント定義 オプジェクトのコンポーネントは , Component(OBJECT) という行以降で , 構造体のメンノヾを列挙して定義する。 OBJECT はオプジェクト名 , ただしすべて 大文字て書くこと。 ■オプジェクトのインタフェイス定義 オプジェクトのインタフェイスは , lnterface (Object) という行以降で , インタフェイス関数のプロトタイプ宣言を列挙することで定義する。 Object はオ プジェクト名 , 初めの 1 文字のみ大文字で書くこと。プログラム中で使うオプジェクト名はこちらで ある。 ■オプジェクトの生成・消滅 オプジェクトのインタフェイス関数として , Object NewObject(... ) : Nothing DeleteObject(Object) : のふたつは必須である。 Object には個々のオプジェクト名が入る。 NewObject( … ) はオプジェクト を生成し , DeleteObject( ) はオプジェクトを消滅させる。 NewObject(... ) の ... の部分はどんな引 数をとってもよい。この引数の型によってたとえば Object NewObjectByName(Name) : のように By 何々という名前を付加してもよい。その場合でも NewObject(...) は用意すること。 一所有権の移動 New および Get で始まるインタフェイス関数の返り値として得られたオプジェクトは , 使用後 , 返 り値を得た側て DeIeteObject する必要がある。逆に G ⅳ e ではじまるインタフェイス関数に引数で与 えられたオプジェクトは , 使用後 , インタフェイス関数の側で DeIeteObject する必要がある。 付録ティスクの deck. h/c や hand. h/c を参照のこと。 ーインタフェイス関数の規約 〇インタフェイス関数の第一引数は必すそのオプジェクトへのポインタになる。このポインタは通 常 this という変数名で , オプジェクト自分自身を指す。ただし , New で始まる関数にはこの規 約はあてはまらない。 インタフェイス関数名はオプジェクト名を含む。たとえばオプジェクト ca 「 d のインタフェイス関 数は何々 Card という名前になる。 コンボーネントの参照関数はコンポーネント名を含んだ名前にする。たとえばカードのランクを 参照する関数なら , RankOfCa 「 d という名前になる。 ドなら真を返す関 数は , SameCa 「 d という名前になる。 ■組み込みオプジェクト 次のオプジェクトははしめから組み込まれている。 「無」オプジェクト ( 型 ) Nothing 「無」オプジェクト ( 実体 ) 真偽値オプジェクト ( 型 ) Boolean 整数オプジェクト ( 型 ) lnteger たくなってきます。そうすれば , 名前にい ちいち card をつけなくても , 構造体 CARD に関連する関数だということがわかっても らえるからて、す。 しかし , 残念ながら C て、は構造体のメンバ として関数を含めることはて、きません。ど うしても含めたいときには関数へのポイン タをメンバとして含めることになります。 これだとポインタの領域のメモリが構造体 ひとつひとつごとに消費されてあまりうれ しくありません。 一方 , C 十十て、は構造体のメンバに関数を 含めることがて、きます。もちろん構造体の 大きさがそのために大きくなることはあり ません。そこに書かれたメンバ関数は名前 が適宜変形され , コンパイラによって正し く処理される形になってくれるのて、す。 こて、は詳しく述べませんが , C 十十コンパイ ラが自動的に名前に card を付加するような ものて、あると考えればよいて、しよう。 変数と関数の両方をひとつに集めるのは , 想像以上に大きな意味を持っています。デ ータを保持する変数と , どのような操作を 行うかを示す関数をひとつに集めると , 単 に複雑なデータが表現て、きるだけて、はなく , その型がプログラムの中て、どういう役割り を果たすものなのかがはっきりしてくるの て、す。 「変数と関数」は「データとインタフェイス」 あるいは「コンポーネントとインタフェイス」 と呼ぶことがて、きるて、しよう。 SmaIItaIk な ら「インスタンス変数とメッセージ」と呼ぶ ところて、す。いすれにせよそのモノが , ・何でできているか ・どう使うのか をはっきりさせることはとてもたいせって、 す。このふたつがはっきりすれば , そのモ ノは「オプジェクト」と呼ぶにふさわしいも のとなってきます。 C 十十て、は上記の 2 点は それぞれ , ・メンバ変数 ・メンバ関数 ちょっと注意 こて、はオプジェクトの 基本的な概念のみを扱っています。継承な どの概念については触れません。また機会 があったら紹介することにします。 プログラミングの工ッセンス 55

2. 月刊 C MAGAZINE 1992年6月号

とえば , GetCardOfDeck ( ) て、は得られるカ ードの所有権は Deck を離れますが , Get の つかない CardOfDeck( ) て、は所有権は離れ ません。 DeleteCard ( ) の責任はまだオプジ ェクト Deck 側にあるのて、す。 C 十十て、は AUTO 変数にとられたオプジェ クトは消滅時に自動的に DeIete されるのてす が , オプジェクトレンズは C の機構しか使え ないのて、 , プログラマが自分の責任て、 DeIe te の管理をしなくてはなりません。関数名に Give や Get がついたら所有権が移動するとい うのは , Delete の管理をしやすくするための オプジェクトレンズて、の約束ごとて、す。 プイヤーは何でできているか 次はプレイヤーて、す。プレイヤーは何て、 て、きているて、しようか。プレイヤーの本質 は何て、しようか。考えてみましよう。 まあ , 名前は必要て、しよう。名前もひと Fig. 2 オプジェクト Ca 「 d を作る 実世界 つのオプジェクトて、す。プレイヤーは配ら れたカードの集合 ( 手 ) をひとつ持っていま す。 プレイヤーの年齢は ? 性別は ? それ らは , 入れたかったら入れてもかまいませ ん。筆者はそれらのデータをプレイヤーの トラ コンポーネントに入れませんて、した。 ンプ占いなどをオプジェクトて、表現するな ら年齢・性別も重要な要素になるかもしれ ませんね。 そんなときには年齢・性別もプレイヤー のコンポーネントに入れるといいて、しよう。 オプジェクトのコンポーネントを何にする かは , とくに決められているわけて、はあり ません。すて、に決まっている結果をなぞる のて、はなく , プログラムを書く人自身が「こ うしよう」と決めてやるのて、す。どういうオ プジェクトになるかは設計者しだい うわけて、す。そこにこそプログラミングの 実際 , 今回このトランプゲームをオプジ ェクトレンズて、記述しているとき , 妙に心 が騒いだものて、す。「カードの山をカードと は別のオプジェクトにしたほうがいい」とか 「おお , プレイヤーというオプジェクトを作 ればいいんだ」とか , 実世界をコンピュータ 上に移す作業は胸がドキドキするような体 験て、した。 とくにオプジェクトレンズ自身 をデザインしながらのトランプ作りはなか なか楽しいものて、した。 プレイヤーのインタフェイスを考えます。 プレイヤーの名前を取得するインタフェイ スは必要て、すね。ほかの人に名前がわから なくなってしまいますから。問題は , プレ イヤーが今持っている「手」を得るインタフ ェイスて、す。 プレイヤーの「手」はそのプレイヤーが今 プイヤーはどう使うか 面白さがあるのて、す。 コンピュータの世界 Component (CARD) Suit suit; Rank rank; lnterface(Card) SuitOfCard ( ) ; IsSameCard( ) ; RankOfCard( ) ; Fig. 3 オプジェクト Deck を作る 何でてきて いる ? 実世界 カードの 「山」 何でできて いる ? ( コンポーネント ) どう使う ? ( インタフェイス ) ランクと スート ランクを見る スートを見る 調べる 等しいか カードが ( コンボーネント ) シャッフルする ( インタフェイス ) どう使う ? カードをとる コンピュータの世界 Component (DECK) Card card;[53], lnteger top, lnterface (DECK) ShuffIeDeck( ) ; GetCardOf Deck( ) ; 58 C MAGAZINE 1992 6

3. 月刊 C MAGAZINE 1992年6月号

うにはまず登場人物は何かを考えます。登 ちょっと考え方を変えましよう。トランプ フのプログラム 場人物・・・・・・つまり関連するオプジェクトを のカードの本質は何て、しよう ? 紙て、て、き ンプのオプジェクト化 設計するところから始まるのて、す。問題 1 て、 ていることは本質的て、はありません。プラ 今月のプログラムは問題 1 を大幅に拡張 はカード君だけを考えましたが , 今度はそ スチックて、もいいし , 木て、も石て、もいい し , 「トランプのゲーム」をオプジェクト指 の親類縁者も含めて設計します。 ってことはカードの材質は問題じゃないっ 向風に記述したものて、す。オプジェクト指 トランプゲームに登場するオプジェクト てとて、す。 向「風」なのは , 今回のプログラムは C 十十て、 は何て、しよう。 とにかく登場しそうなモノ トランプのカードの本質は何て、しよう ? はなくて C て、書いたためて、す。 C て℃十十の を全部あげてみましよう。足りなければま 本質とは何ぞや ? これがなかったらもう まねごとをやってみました。 こて、はちょ た追加すればいいのて、す。 トランプのカードとはいえない性質のこと っと特殊な C のコーディングを行います。 うーん。まずトランプのカードは必須て、 て、す。問題 1 て、考えましたからもうわかりま のコーディング方法に便宜上 , オプジェク しよう。それからゲームを行うプレイヤー すね。 ート , ダイヤ , クラブ , スペード , トレンズ (Object Lens) と名前をつけまし かな。プレイヤーは配られたカードを持っ というスートと , A, 2 , 3 , ・・・ J , Q, K と た。オプジェクトレンズの詳細は Fig. 1 をご から , それをひとつのオプジェクトにして いうランクの組み合わせがトランプのカー 覧ください。オプジェクトレンズは今回の もいいだろう。 ドの本質て、す。 それはいわば手というオプジェクトだな。 テーマ「コンポーネントとインタフェイスを 一枚のカードは必ずひとつのスートとひ 集める」ことを主眼にコーディングをします。 そしたら , プレイヤーに配って残ったカー とつのランクて、て、きています。たとえばス オプジェクトレンズて、プログラムを書く ドを積んて、おく山もひとつのオプジ土クト ペードの A なら , スペードというスートと A には , List 2 をインクルードしてそこに書か になるかもしれない。よし , まずはこのく というランクを持っています。スートやラ れているマクロ Component, lnterface を使 らいか。 ンクも後ほどオプジェクト化することにし カードから順に詳細な検討を行ってみま 用します。マクロ Component 以降にはその て , とりあえずこれて、いいて、しよう。カー オプジェクトのコンポーネントを , マクロ しよう。検討のポイントは , 先ほども述べ ドはスートとランクというふたつのオプジ たようにふたつあります。そのオプジェク lnterface 以降にはそのオプジェクトのイン ェクトて、作ることにしました。 タフェイスを記述します。 Component 以降 トが , カドはどう使うか にメンバ変数を , lnterface 以降にメンバ関 何でできているか ( コンポーネント ) 数を書くようなつもりて、書きます。詳しく どう使うか ( インタフェイス ) カードはどう使うのて、しようか。今度は はソースプログラムを見てください この 2 点をチェックするわけて、す。 オプジェクトレンズは C 十十のクラス定義 カードのインタフェイスを考えます。 の機能を C て、真似しようというものて、す。 カドは何でできているか カードは見ることがて、きます。見て , れはスペードだとか工ースだとか判断する ういうコーディングが直接役に立つかはわ カードは何て、て、きているのて、しようか。 かりませんが , ひとつの実験として参考に ことがて、きます。つまりそのカードのスー カードのコンポーネントを考えます。トラ トが何て、あるか , ランクが何て、あるかを知 してください ンプのカードは紙て、て、きています。確かに るインタフェイスが必要になるわけて、す。 トンプの登場人物 現実のカードはそうて、す。しかし今やろう スートやランクの値を変更するというイ としているのはトランプのカードをプログ ンタフェイスは不要て、す。だって , 普通ト ラム上のオプジェクトにすることて、すから , : クト指向てプログラミングを行 ランプのゲーム中にカードを書き換えたり しませんから。あとは , すべてのオプジェ object. h C 言語でオプジェクト指向風なプログラムを書くためのヘッタ ( 一部 ) クトに共通の , カードを作成するインタフ ェイスとカードを削除するインタフェイス が必要て、す。まあ必須なインタフェイスは このくらいかな。 先ほどはカードをシャッフルするという インタフェイスも考えましたが , 今度はそ List 1 : #define Component(sname) 2 : #define lnterface(class) 3 : #define New0bject(sname) 5 : #define N0thing void 6 : typedef int Boolean; 7 : typedef int lnteger; typedef struct sname { } *class; (struct sname *)NewBySize(s izeof(struct sname)) 56 C MAGAZINE 1992 6

4. 月刊 C MAGAZINE 1992年6月号

督懾 9 kSSemlCe 0 どんなカードを持っているかを表わします。 だから本来「手」はプレイヤー以外に見せる べきて、はありません。したがって , 「手」を 得るインタフェイスは作らない しようか。しかし今回はゲームの途中て、ユ ーザに「いまあなたが持っているカードはこ れこれて、す。どのカードを出しますか ? 」と いう間いを発行するつもりて、すのて、 , 「手」 そほかのオプジェクトたち なりました (List 7 ) 。 以上から , プレイヤーもオプジェクトに プイヤーのオプジェクト化 します。 を得るインタフェイスは残しておくことに 便なプロファイラ れ , オプジェクトの消去は Delete ( ) て、行わ の生成はすべて関数 NewBySize( ) て、行わ オプジェクトレンズて、は , オプジェクト す。 数の呼び出された回数を記録するツールて、 なツールが付属しています。これはある関 の C コンパイラにはプロファイラという便利 I-C 86 ver 3.30 試食版を使用しました。 今回のトランププログラムの作成には LS 解て、きると思います。 ログラムといっても C なのて、すから容易に理 さえ理解すれば , オプジェクトレンズのプ object. h のマクロ展開と関数名のつけかた 照してください は付録ディスク内のソースプログラムを参 (t) , 審判 (Judge) などを作りました。詳しく 名前 (Name), ランク (Rank), スート (Su オプジェクト ? ) として , ゲーム (Game) , そろってきました。このほかの登場人物 ( 登場 プレイヤー (Player) とオプジェクトたちが カード (Card), 山 (Deck), 手 (Hand), player. h プレイヤー 1 : Component(PLAYER) Hand hand : Name name ; Interface(PIayer) 円 ayer NewPlayer(Name) ; Hand0fPlayer(Player) ; Hand Name0fPIayer(Player) ; Name Nothing DeletePlayer(Player) ; 8 : 7 : 6 : 5 : 4 : 3 : 2 : List きました。 調べていくっか重大なバグをとることがて、 し回数は等しくなるはずて、す。この対応を 点て、は NewBySize( ) と DeIete( ) の呼び出 れます。すなわちプログラムが終了した時 付録ディスクにはオプジェクトレンズの 付ティスクの使い方 う関数の一覧を作成してみましよう。そ ラムを見直して , ある構造体とそれを扱 ■【実践】これまであなたが書いたプログ を作りますか。 てみましよう。あなたならどんな構造体 「いろはカルタ」に変えて構造体を設計し ■【練習】問題 1 の「トランプのカード」を ・実践課題 す。 ソースて、遊んて、いただきたいと思っていま のサンプルプログラムはゲームて、遊ぶより , どおもしろいゲームて、はありません。今回 ものて、す。はっきりいってそれて、遊べるほ いカードを出した方が勝ち , という単純な に手持ちのカードを一枚ずつ出し合って強 ゲーム自体はコンヒ。ュータと人間が同時 て、表示しますのて、 , 機種依存はありません。 まります。カードの表示などもすべて文字 ヒ。ュータを相手にしたトランプゲームが始 e が作られます。 game を実行すれば , コン におき , そこて、 make を実行すれ xgame. ex すべてのソースをひとつのディレクトリ ています。 ランプゲームに関連する全ソースが含まれ 基本ファイル object. h と object. c のほか , ト れは実世界の何をコンピュータの世界に 移したものですか。 ■【挑戦】ゲームには乱数がつきものです。 乱数発生装置というオプジェクト Random を設計しオプジェクトレンズコーディ ング規約に従って random. h と random. c を 作ってみましよう。完成したら deck. c 内の 関数 ShuffIeDeck ( 収録ディスク参照 ) が R andom を利用するように修正してみまし ■【応用】本文に登場したオプジェクトた ちを C 十十で記述してみましよう。 今回は「集める」というテーマて、オプジェ クト指向について考えました。あなたの解 こうとしている問題にはどんなオプジェク トが登場するて、しようか。そのオプジェク トは何て、て、きており , どんな風に使うもの . て、しようか。オプジェクトという観点 , す なわちコンポーネントとインタフェイスを 軸に問題を見直すことは問題の整理のひと つの方法て、あることがおわかりになったて、 しようか。 さて , 次回は仮想化というテーマをとり あげましよう。仮想記憶とか仮想データ型 とか , コンヒ。ュータの世界て、は「仮想」とい う言葉がよく登場します。「仮想化」とは , 実際には〇〇て、はないのに , あたかも〇〇 て、あるかのように見なすことて、す。次回は この「見なす」ことをめぐってプログラミン グの工ッセンスを探ってみることにします。 次ロは どうぞお楽しみに プログラミングの工ッセンス 59

5. 月刊 C MAGAZINE 1992年6月号

川Ⅱ 9 0 eck から Hand に移す必要が生じます。オプ ... lnterface (Card) の部分が構造体の宣言に のインタフェイスは「カードの山」というオ ジェクトレンズて、はそれを Get 何々 ( ) と Giv なり , lnteface (Card) 以降は関数のプロト プジェクトのインタフェイスにしようと思 e 何々 ( ) という名前の関数て、表現していま タイプ宣言になることがわかると思います。 こには入れません。 うのて、 , オプジェクト名の Card はカードを表わす構 す。 カードのオプジェクト化 「山からカードをひとつもらい」という部 造体 struct CARD へのポインタ型になりま 分は GetCardOfDeck ( ) という関数て、実現し す。 以上て、「カード」を表すオプジェクト Card ます。「カードを手に加える」という部分は さてカードのコンポーネントとインタフ GiveCardToHand( ) という関数て、実現しま が作られました (Fig. 2 参照 ) 。 ェイスを考えたところてプログラムにして す。ちなみに「プレイヤーの手」という部分 みましようか。 List 3 が , カードをオプジェ は , HandOfPIayer( ) という関数て、実現し クトにするヘッダファイルて、す。カードの 山手 ています。 データは , スートとランクがそれぞれ Suit と 一枚の「カード」がオプジェクトになった Get 何々 ( ) や Give 何々 ( ) て、所有権が移動 Rank というメンバになっています。またス ところて、 , カードの集合を作りましよう。 します。たとえば上の例て、はカードの所有 ートとランクのそれぞれの値を得るインタ プレイヤーにカードを配る元の「山」と , ゲ 権が山から手に移動しています。あるオプ フェイスは , SuitOfCard と RankOfCard と ジェクトの所有権とは , そのオプジェクト ームのプレイヤーが持つ「手」をそれぞれオ して記述されていることがわかると思いま を DeIete する責任のことて、す。たとえばプロ プジェクトにしましよう。山は Deck, 手は す。カードの作成と削除はそれぞれ NewCa グラム終了時に DeIeteHand( ) が実行されま Hand とします (List 5 , List 6 , Fig. 3 参照 ) 。 rd と DeIeteCard て、す。このほかにもいくつ すが , そのとき DeleteHand() の中て、は , そ こて、 , オプジェクトの所有権の問題が生 かインタフェイスが増えていますが , 解説 れまて、に GiveCardToHand( ) 経由て所有権 じます。「山からカードを一枚もらい , その は割愛します。 が渡されたカードについて責任を持って De カードをプレイヤーの手に加える」という List 3 に記述されている Card というオプ 操作を実現しようとすると , Deck のコンポ IeteCard() してあげる必要があります。 ジェクトは C のプリプロセッサによって Lis Get や Give の有無に注意してください。た ーネントの Card オプジェクトをひとつ , D t 4 へと展開されます 0Component(CARD) ca 「 d. h の展開結果 card. h カード 4 List List 1 : typedef struct CARD ( Suit suit; 2 : rank : Rank 3 : 4 : } *Card : NewCard(Suit, Rank) : Card 5 : De 1 eteCard (Card) ; VOid 6 : Rank0fCard (Card) ; Rank Suit0fCard(Card) ; Suit 8 : B001 ean I s SameCard (Card, Card) : 9 : B001 ean I sJokerCard (Card) ; 10 : GetNameOfCard(Card) : Name 11 : 1 : Component(CARD) suit; Suit 2 : Rank rank ; 3 : 4 : Interface(Card) NewCard(Suit, Rank) ; Card 5 : N0thing DeIeteCard(Card) ; 6 : Rank0fCard(Card) : Rank 7 : Suit0fCard(Card) ; Suit 8 : BooIean IsSameCard(Card, Card) ; 9 : Boolean IsJokerCard(Card) : 10 : GetNameOfCard(Card) : Name List hand. h 「手」 deck. h カードの「山」 List 1 : Component(DECK) Card card [MAX—DECK] : 2 : I nteger tOP : 3 : 4 : Interface(Deck) NewDeck(N0thing) : Deck ShuffleDeck(Deck) ; Deck 6 : GetCardOfDeck(Deck) : Card 7 : B001ean IsEmptYDeck(Deck) : 8 : lnteger MaxDeck(Deck) : 9 : N0thing DeleteDeck(Deck) : 10 : 1 : Component(HAND) card - card [MAX-HAND] : 2 : 3 : lnteger count; 4 : Interface(Hand) NewHand(Nothing) : 5 : Hand Nothing DeleteHand(Hand) : 6 : G i veCardToHand (Hand, Card) : 7 : Hand Ge tCardFromHand ( Hand, Card) : 8 : Card GetIndexedCardFromHand(Hand, lnteger) : 9 : Card lnteger MaxHand(Hand) ; lnteger CountHand(Hand) : GetName0fHand(Hand) : 12 : Name プログラミングの工ッセンス 57

6. 月刊 C MAGAZINE 1992年6月号

ダの フィンロ あつばれ ご意見番 「ポインタの配列が狂って・・・・・・」 イラスト / 椙村嘉ー 万能て、ある , 人間より賢い , といったイメ もうひとつ凄いと思ったのは , HAL がチ ず , はじめに ージが生まれるのは自然な連想だ。電脳と ェスを指すシーンて、ある。どんなシーンか いう言葉があるくらいだから , 脳に代わる というと , コンビュータがチェスの駒を実 というイメージもある。さらに , 知能を持 まず 4 月号特集記事に関して。 NIFTY-S 際に動かしていたのて、ある。何が凄いかと erve のプログラマーズフォーラム ( FPROG ) っ存在へとイメージは広がり , 結局のとこ いうと , 今あるコンピュータのチェスとい には多数の感想をいただきありがとうござ ろ「得体のしれない」といった形容詞て、表現 えば , 画面上にグラフィックスて、チェスの いました。以前はあら探しに燃えていた私 されるようになってしまう。これがいまだ 盤を描いて , その上にチェスの駒を表示し て、すが , 例の記事も「あら」だらけて、 , どう に多くの人の持つイメージて、はないか。 て・・・・・・というユーザインタフェイスだ。実 も申しわけありません。 物の駒をマジックハンドて、動かそうなんて 古典的すぎるかもしれないが , 「 2001 年宇 宙の旅」には , HAL9000 シリーズというコン 48 ページて、「 & & 」を「論理 OR 」と説明して 発想は , なかなか出てこない いるが , これは「論理 AND 」の誤り。なぜこ マルチメディアという言葉はかなり普及 のような情けない誤りをしたのか , 定かて、 したようだが , その実態は不明瞭て、ある。 はない。現実には , & と & & の間違いをした やっと動画 , 音楽が扱えるようになり , 音 経験はあるが , 論理 OR のつもりて、 & & と書 声て、メールを送る程度のものて、ある。この ことはない。よくよく考えてみたが , あたりの壁を超えることがなかなかて、きな おそらく「 & & 」という文字列が , 論理 AND い。実用的な入力装置は , せいぜい電子べ という概念そのものに直結していたため , ンが普及するかどうか , というところて、あ 「論理 AND 」「論理 OR 」という言葉にイメージ る。カメラからの画像を分析して , 入力文 字データとして取り込んだり , 出力をメカ が対応しなかったのだと思う。また , 49 ペ ニカルアームによって「動作」として表現す ージの「 getchar の記法」は「 fopen の記法」の る , といった方向へはなかなか実用化が進 誤りて、ある。お詫びの上訂正させていただ まないようだ。実際の動きを入出力として く。そのほか , 細かい間違いがまだあると 応用する研究は , もっと積極的になって欲 思われる。見つけた方はぜひご指摘いただ しいものて、ある。 感想の中て、 , とくに賛同者が多かったの ピュータが登場する。 OS ー 9000 という OS が 古典的 , SF 的なイメージはさておき , 最 は , 「プログラミングにはセンスが必要だ」 発表されたときは , 「これは HAL9000 シリー 近の小説の中には , もっとリアルな存在と ズへの伏線か」と冗談されたものだ。映画て、 という点て、 , これが実地体験している人た して , 違和感のない小物として登場し始め は , HAL が乗組員の会話を唇の動きて、読ん た。たとえば PC / AT の上て、 , スプレッドシ ちの共感を呼んだということは , 非常に重 大な意味を持っているのて、はないかと思う。 て、しまうシーンが印象的だった。こんなと ートやエデイタが動いている , というシー ころに注目する人は少ないかもしれないが , ンて、ある。 SF て、はなくて , 日常生活そのも ンピュータのイメージ 目に相当するセンサーを使って唇の動きを のの描写としてパソコンが使われるのだ。 データとして入力すること自体が , 非常に 日本の小説て、は , このような描写をまだあ 画期的な方法だと思ったのだ。もちろん HA 昔はコンピュータが出てくる小説といえ まり見た記憶がないのだが , 多分それは私 ば SF だった。コンピュータという存在その L は音声入力装置も備えている。音声によっ があまり小説を読まないからかもしれない ものが SF 的な要素を持っているのて、 , 当然 て命令が入力されるとき顔の画像をデータ あえていうならマンガの中て、はパソコンは , かもしれない。確かにコンヒ。ュータは人間 もはや机や椅子と同じレベルの単なる小物 として蓄え , 画走と音声との対応を自己学 にて、きないことを軽くこなす。そこから , 習したのだろうか。 として登場してくる。 第 2 回 ◆◆◆ ( ◆◆◆◆◆ 、◆◆◆◆◆◆ ◆◆◆・◆ ◆◆・ 140 C MAGAZINE 1992 6

7. 月刊 C MAGAZINE 1992年6月号

COMNTER LANGUAGE C 十十でエラー表示を き MO G リ 楽にやろう 0 epo 「 ng Easy 0 po 市 C 十十 は LA [ S Bruce E e レ岩谷宏訳 (COMPUTER LANG UAGE, FEB. 182 ) 提携記事 使いやすく高機能なエラー報告の作例 , そしてあの 厄介な iost 「 eam クラスを使いこなすコツを学ぶ C 十十て、新しいクラスを作るたびに , 何ら トラクタは , 文字列引数のアドレスをクラ ればよいのて、すが , べースクラスやユーザ かのエラー報告のコードが必要になるて、し スのメンバて、ある msg というポインタに代入 定義型のメンバの初期化が行なわれる場合 よう。しかし , それが意外と簡単て、はない するだけて、す。この代入は , コンストラク こて、それらのコンストラクタがコー は , のて、 , 工ラー報告が必要なのに省略するこ タの宣言の頭にコンストラクタイニシャラ ルされるのてす。ューザ定義型て、あれ , 内 とがあるし , また現状て、はエラー処理のた イザを並べて書く , という方法て、行なって 蔵型て、あれ , すべてのメンバをコンストラ めの共通のインタフェイスや形式も私たち います。この場所て、べースクラスやメンバ クタイニシャライザとして列記して初期化 は持っていません。本稿て、は , 工ラー報告 の初期化がて、きるのてす。 すると , コンストラクタ本体としてはメン のためのクラスを 2 種類ご紹介しようと思い 〔訳注 : コンストラクタイニシャライザに バがすて、に初期化されている , という前提 ます。最初のは , おなじみの printf ( ) ふうの ついては , たとえば ARM ( 『 The Annotat に立てるから便利なのて、す。 やり方て、す (ANSI C のライプラリの va ar 〔訳注 : コンストラクタイニシャライザ ed C 十十 Reference Manual 』 , Stroustru g の使い方も示します ) 。二つ目は , もっと p, et al : Addison-WesIey) の 12.6.2 を読 によってメンバを初期化すると , この error 強力て、効率的な C 十十の iostream クラスを使 んて、ください。また本誌 ' 91 年 10 月号の連載 handler クラスがまさにそうて、あるように い , クラスの継承によってわすかな変化が 記事「恥ドジ」も参考になります〕。 単純なクラスて、はコンストラクタ本体とし 大きな効果をもたらす , という例を示しま コンストラクタイニシャライザて、は , 今 ては何もやることがない・・・・・・実行本体が単 す ( 今回の例は , iostream ライプラリからの 回はメンバのデータ型が内蔵型の char * て、 なる { } ・・・・・というケースが往々にして生じ 継承て、す ) 。 すから , 単純に引数が代入される , と考え ます〕。 〔訳注 : C のストリーム I/O, C 十十のスト ERROR. H リームクラス , そして UNIX System V の STREAMS におけるストリーム・・・・・・日本語 、、ストリームクの意味は , C/UNIX 界隈て、こ のように , 少なくともく三重化〉していま printf ふうの方法 ERROR. H (List 1 ) は , printf 的なエラー メッセージ表示機能のためのヘッダファイ ルて、す。この error handler クラスのコンス List 1 1 : 〃 : ERROR. H ーー他のクラスの中でエラー管理を行なうクラス . 2 : / /. このクラスは , メンバデータを介するクラスの汎用的利用の例である . 3 : / /. class-msg は , この error handler クラスが使われているクラスの名前とする . 4 : / /. 〔訳注 : 上はあくまでも原則的な使い方 . 本当はどんな文字列でもよい . 〕 5 : 〃 . termi te ( ) の引数の取り方は printf ( ) とまったく同じ . 6 : #ifndef E OR 』 7 : #define ERROR H 8 : 9 : class error—handler { 10 : char * msg; 11 : public: error—handler(char * class msg) : msg(class—msg) { } 12 : VOid message(char * formt_string, 13 : VOid terminate(char * formt_string, ... ) : 14 : 15 : } : 16 : 17 : #endif / / ERROR_H C 十十でエラー表示を楽にやろう 15

8. 月刊 C MAGAZINE 1992年6月号

アルゴリズム 0 テータ構造入門 されています。また , C の標準ライプラリ に含まれる高レベル入出力関数 ( fopen , fp rintf, putc, getc, fclose など ) ては , 独自 にバッファリングを行っています。プログ ラムの例としては , 別のものを取り上げま あるファイルに含まれるデータをある基 準に従って複数のファイルに振り分けたい ことがあります。たとえば , 各レコードに 付加されている分類コードを調べて , 分類 ごとに別のファイルに出力するとい うケースて、す。このとき , 分類コードの種 類が少なければ , あらかじめすべての分類 コードに対応するファイルをオープンして ことがて、きます。 しかし , 分類コードの種類が多い場合に は , この方法て、はうまくいきません。なぜ なら , プログラム中て、 , 同時にオープンて きるファイルの個数には上限があるからて、 ③プロック 52 を読み込む。先頭バッファ ( フロック 25 ) が捨てられ , す。この制限はオペレーティングシステム そこにプロック 52 か読み込まれて末尾に移動される ( Fig. 8 ー⑤に相当 ) によって異なりますが , 多くてもだいたい に相当する操作を Fig. 9 に示します。バッフ 数十個といったオーダーて、す。 て、は , プロック 24 は , すて、に読み込まれて アの実体は移動されずに , ポインタの操作 このようなケースては , データをひとつ いるのて、 , 実際にはディスクから入力は行 だけによって待ち行列が実現されている様 処理するごとに , 分類コードに対応するフ わずに , 待ち行列の末尾に移動します。 Fi ァイルをオープンして , データを書き出し , 子がわかります。 g. 8 ー⑤て、は , プロック 52 をディスクから読 ファイルをクローズする , というのがイー あるプロックがすて、にキャッシュに読み み込んて、いますが , 先頭のバッファ 25 を再 ジーな解決策てしよう。しかし , これては 利用します。プロック 52 は末尾に挿入され 込まれているかを調べるには , リストの頭 データの個数と同じ回数だけファイルをオ からリンクをたどりながらひとつひとつの ます。 ープン , クローズしなければならず , 非常 バッフアをチェックします。この方法て、は , ところて、 , Fig. 8 て、は , あたかも配列を用 に処理時間がかかります。 いて待ち行列を実現しているような印象を キャッシュにヒットするかどうかをチェッ 与えています。単純な待ち行列なら , 以前 クするのに , キャッシュの個数に比例する もちろん , あらかじめデータを分類コー 時間がかかることになります。 ドのキーに整列しておく , という UNIX 風な に説明したようにリングバッフアを用いれ こては キャッシュの個数が少ない場合には , さ 解もありえるて、しよう。しかし , ば , 効率よく実現て、きます。しかし , キャ 何らかの理由 ( データの個数が莫大てある , ほど問題はありませんが , キャッシュの個 ッシュにヒットしたとき , そのバッフアを 数が多くなるとこの時間も無視て、きません。 すべてのデータがそろうまて待っ時間的な 末尾に移動する , という操作があるのて、 , 多数のキャッシュを用いる場合には , ハッ 余裕がない , など ) て , あらかじめ整列して 配列をベースに実現すると , どうしても配 シュ法を用いてヒットしたかどうかのチェ 列内の要素の移動を避けることはて、きませ おくことは不可能て、あるとしましよう。 ックを高速に行えるようにします。 ん。バッフアは , K バイト単位の大きさがあ そこて , キャッシュを利用して出力用の るのて、 , 配列を用いるのは , 実用的て、はあ ファイル記述子を管理することにします。 カ用ファイ丿レの つまり , 1 度オープンしたファイルはてきる りません。 、ンシンク、 だけオープンしたままにしておくわけてす。 このようなケースて、は , 連結リストを用 いると便利て、す。とくに , 任意の要素を末 今まて、お話したファイル入出力用のキャ このプログラムを List 1 に示します。 ini 尾に移動する必要があるのて , 双方向リス ッシュは , UNIX や MS-DOS< は , オペレ t cache, end cache, open file の三つの関 トを用いるのがよいて、しよう。 Fig. 8 ー③ ~ ⑤ ーティングシステムのレベルて、すてに実現 数が外部とのインタフェイスになっていま アルゴリズムとデータ構造入門 65 Fig. 9 双方向リストによる LRU 25 24 リストの頭 18 がこの順で並んでいる ( Fig. 8 ー③に相当 ) ①初期状態。待ち行列には 24 , 25 , 18 25 24 0 フ、ロック 24 を参照した。プロック 24 は末尾へ移動される ( Fig. 8- ④に相当 ) 52 24

9. 月刊 C MAGAZINE 1992年6月号

「 WATCOM C / 386 」 株ライフボート 株ライフポートは , カナダの WATCOM 社 とソフトウェア開発と販売の提携契約を締 結し , 80386 / 486 専用の 32 ビットコンパイラ WATCOM C / 386 日本語版の販売を開始した。 WATCOM C / 386 は , CPU80386 / 486 の 32 ビットネイテイプモード用コードを出力 するネイテイプコンパイラ。コンパイラ自 身が 32 ビットネイテイプモードて、動作する ため , 従来より大きなソースファイルがコ ンパイル可能となる。おもな特徴は以下の とおり。 ・ 32 ビットリニアアドレッシングを採用し , 64K バイトや 640K バイトのメモリ制限を 受けないプログラムを作成可能 ・ネイテイププロテクトモードて、動作する コンパイラとリアルモードて、動作するコ ンパイラの 2 種類を搭載 ・リエントラントな構造のコードを出力し , 割り込み処理など複数スレッドの実行が 同時にアクテイプになるソフトの開発が 可能 ・ ROM 化ユーティリテイ「 LINK & LOCA TEPM 」をバンドルしたパッケージ「 WA TCOM C386/ROMabIe 」も用意されてい る く動作環境 > ・対応機種 PC ー 9801 シリーズ , J ー 3100 シリ ーズ ,PC/AT マシン , AX マシ ン , PS/55 シリーズ ( いずれも CPU80386 以上搭載機に限る ) ・対応 OS MS-DOS Ver. 3.1 以上 ・必要ソフト DOS/4G ( 専用 DOS-Extender) ・必要メモリ 2.6M バイト以上 C MAGA Borland C 十十 Ver. 2.0 以上 (Windows SDK が必要 ) ・対応コンパイラ MS-C Ver. 5 . 1 / 6 . 0 ・必要メモリ 2.6M バイト以上 ・対応 OS MS-Windows Ver. 3.0 以上 く動作環境 > ルード可能 ・自動生成コード中に外部 C コードをインク AKE ファイルなども自動生成可能 ・ C ソースコードのほかへッダファイル , M 動作確認が可能 コンパイルすることなく , プログラムの ・アニメーションテストモードを搭載し , ドを出力する。おもな特徴は以下のとおり。 タイル , ダイアログを設計 , C のソースコー Windows アプリケーションのメニュー , ス 同ソフトは , Windows 上のマウス操作て、 ノし、 0 MAKER Professional を発志した C 言語ソース自動生成プログラム Windows 工クセルソフトは , Windows3.0 対応の 工クセルソフト株 「 Windows MAKER ProfessionalJ TEL 03 ( 3293 ) 4711 く価格 > 189 , 000 円 く価格 > 198 , 000 円 問い合わせ先工クセルソフト株 〒 108 東京都港区三田 2 ー 10 ー 5 工ル・アルカサル三田 403 TEL 03 ( 5440 ) 7875 「 BGM / グラフ作成プログラム 2.0 」 「 wndow & Menu 2.0 」 「 Key & Display 2.0 」 「 CCF / 総合コンソールコントロール ライプラリ 2.0 」 株ティップス 株ティップスは , PC ー 9801 シリーズ用 C 言 語ライプラリとして「 BGM / グラフ作成プロ グラム 2.0 ( 以下 BGM ) 」 , 「 Window & M enu 2.0 ( 以下 Window & Menu) 」 , 「 Key & Display 2.0 ( 以下 Key & Display) 」 , 「 C CF/ 総合コンソールコントロールライプラリ 2.0 ( 以下 CCF ) 」の 4 製品を発売した。それぞ れの特徴は以下のとおり。 BGM 円グラフ , 棒グラフ , 折れ線グラフなど 13 種類のグラフを作成するライプラリ。グ ラフ作成関数のほかに , グラフィック関数 , マウス関数も装備。別売の「 Graphic & M ou 」ライプラリとあわせて , BGM / グラフ 作成プログラム 2.0 と同様の機能を実現す る「 BGM/Kit 」も用意されている。 Window & Menu テキスト画面上て、オーバラップ可能なウ インドウを最大 100 個まて、オープンして操作 するライプラリ。スクロールウインドウや パネルウインドウ ( リアルタイムに変化する 情報を表示可能 ) など使用目的に応じて多種 のウインドウの使い分けが可能。 Key & Display ファンクションキー対応の key 入力 , 文字 表示 , カーソル制御 , 日本語 FEP 制御など のライプラリ。 key 入力は単純な key データ の読み取りから入力時の編集機能をサポー トしたものまて用意されている。 CCF プログラムのユーザインタフェイスをサ ポートするライプラリ「 Window & Menu 」 , 「 Key & Display 」 , 「 Graphic & Mouse 」に 含まれる関数に加えて , PC ー PR 系に対応し たプリンタ制御関数をサポート。 く動作環境 > ・対応機種 PC -9801 シリーズ ・対応 OS MS-DOS Ver. 3.1 / 3.3 ・対応コンパイラ MS-C Ver. 6.0 QuickC Ver. 2.0 Turbo C Ver. 2 . 0 Turbo C 十十 Ver. 1.1 (BGM のみ MS-C Ver. 5.1 にも対応 ) WATCOM C386 / ROMabIe 298 , 000 円 間い合わせ先株ライフポート 〒 101 東京都千代田区神田錦町 3 ー 6 146 C MAGAZINE 1992 6

10. 月刊 C MAGAZINE 1992年6月号

の関数を登録します。 exit ( ) は main ( ) が正常に終了するときに も , コールされます。 exit ( ) がコールされ ない唯一の場合は , ライプラリ関数 ab 。 rt ( ) をコールしてプログラムを終えたときて、す (abort( ) は static なオプジェクトのデストラ クタコールをスキップするのて、 , C 十十て、は 勧められない乱暴な方法て、す ) 。 ioserror の実装 以上のような情報がすべて , IOSERROR. CPP (List 6 ) に盛り込まれていることが , お 分かりと思います。このファイルて、真先に 目につくことは , これが ioserror を指すポイ ンタを収める , eh list という名のコンテナ クラスて、あることてす oehandler list という 名の , このクラスのたったーっの static なイ ンスタンス ( このファイル内て、のみ可視 ) を , , こに ioserror クラスのオプジェクト 作り 〔の this 〕をすべて , その生成時に登録しま す。この登録はこ覧のように , ioserror のコ ンストラクタの中て、行なわれます。この eh list: :Register() という関数コールは , オプジェクトのポインタ (this) を , 配列に収 めるだけて、す ( 配列の境界オーバのチェック も行なう ) 。この実装は単純て、すが , より一 般的には , リンクトリストを使ってもよい て、しよう ( そうしてもインタフェイスは変わ りません ) 。 eh list のコンストラクタは atexit ( ) をコ ールして , 〔 exit ( ) 時にコールされる関数と : dump ( ) 関数を登録しま して〕 eh list: す。すると , プログラムの終了時にはすべ ての ioserror オプジェクトがダンプされま . dump ( ) のようなメ す。しかし , eh list: ンバ関数を , atexit() のような普通の関数 の引数にすることは , C 十十て、は普通は不可 能て、す。 C 十十て、は , メンバ関数のコール と , それが属するオプジェクトとが , 密接 に結びついているからて、す。て、はなぜ , こて、はそれがて、きているのて、しよう ? eh list : : Register( ) と eh list : : dum p ( ) は , static なメンバ関数として宣言され ています。 static なデータメンバと同様に static なメンバ関数はクラス全体に対して働 き , static て、ないデータメンバにはアクセス て、きません〔 static て、ないデータメンバ = 個々 のオプジェクトごとに作られるデータメン バには , アクセスする必要がないのだか ら〕。普通のメンバ関数のように , オプジェ クトのアドレスを隠れ引数〔コンパイラが メンバ関数に対して暗黙裡に渡している引 数〕として渡す必要もありません。 むしろ static なメンバ関数は , 普通のグロ ーバルな関数と似ていて , ただ名前がクラ ス内部に隠される , という点だけが違いま す。 static なメンバ関数は , 普通の関数と同 じようにコールて、きますが , そのとき eh li : eh list ( ) の例のように , スコープ指 st : 定演算子を使ってクラス名を指定すること 2 : 5 : 9 : 11 : 12 : 13 : 14 : 16 : 17 : 18 : 19 : 20 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : 29 : 30 : 31 : 32 : 33 : 34 : 35 : 36 : 37 : 39 : 41 : 42 : 43 : 45 : 48 : 49 : 50 : 52 : 57 : 58 : 59 : } List 6 IOSERROR ℃ PP iostr m を使うエラーハンドラの実装 1 : / / : IOSERROR. CPP ー #include ” ioserror. h ” 3 : #include く stdlib. h> 4 : #pragma warn -inl / / "not inline ”というメッセージを無視する 6 : / / もっと本格的な実装では , 固定サイズの配列は使うべきではないだろう . 7 : class eh—l ist { / / ioserror 用のコンテナクラス 8 : / * このコメントアウトした部分はテ・イスクで提供されたオリシ・ナルハ・一シ・ヨン .. コンハ。イラが ' eh list: :size' is not accessible というエラーメットシ・を出し , iostest の in ( ) の内容を実行後 , 暴走に突入する . これはコンハ。イルはできるが , 出来上がった . EXE は , 15 : / * 以下は COMPUTER LANGUAGE 92 / 2 月号に載っているハ・一シ・ヨン .. static int cursor; StatiC ioserror* 1 istcsize] ; enum { S i ze = 100 } ; 〃 * * * ェラーハント・ラの存在許容最大数 コンハ。イルできない . ( たぶん , ' list ' が不完全宣言なので sizeof ( eh ー list ) が不正になるから ? ? ) 事 / static ioserror* listC]; / / * * * ' size' はここでは参照できない * static int cursor; 21 : public: enum { S i ze = 100 } ; 〃 * * * ' size' を public 部に移す eh-l ist() { 〃 exit ( ) に際して du 叩 ( ) を実行する atexit(eh—list: :dump); / / ェラーハント・ラが新たに作られるたびに登録する static VOid Register(ioserror* (h) { if(cursor く size) 1 istCcursor + + ] ニ eh; else clog くく "increase eh—list size" くく nl; / / すべてのエラーハンドラの内容をダンプする static void dump() { whi le(cursor-- > の 1 ist[cursor]- 〉 du 叩 () ; 40 : / / static なデータメンパの定義 ( 0 に初期化する ) ioserror* eh list::list[eh list::size] = { 0 } ; 〃 * * * ェラーの出る行 int eh list: :cursor 44 : static eh_list ehandler list; 〃このファイルの中でのみ可視 55 : / / したがっていかなるエラー情報も失われない . 54 : / / 最初にすべてのエラーハンドラのデータをダンプする . 53 : / / プログラムを終了させるエラーハンドラが eh_list::Register(this); / / static なメンバ関数をコール : ostrstream(msg, bsize), classname(class—name) { ioserror: : ioserror(char * class_name) 47 : / / オブジェクト (this) を eh_list に登録する : 46 : / / ostrstream を , msg バッフアに出力するように初期化し , return OS ; / / コンハ。イラに文句を言われないためのタ・ミーの return 文 exit(l); 56 : ostream& terminate(ostream& (s) { / / これはマニピュレータ C + + でエラー表示を楽にやろう 19