00 C 十十クラスライプラリ概論 きには , そうしたオプジェクトの作成が不経済にな こうしたものを考慮する必要がな ( を不明瞭にし , ることもある。式をサポートしているほとんどのラ という誤った信念をプログラマに植えつけ , ときに イプラリクラスには , そうしたプログラミングにお は矛盾した振る舞いをもおこす , という理由から取 ける不経済を避ける助けとなるだけの能力がある。 り除かれた。 これら可変サイズのオプジェクトクラスは C 十十に 例をあげると ,lntegera, b, c ; b 十 a ; というコードにおいて , 加算演算子は a と b て、きるだけ適合されている。これらのうちほとんど との和を求めるために呼び出され , その結果を入れ のクラスは , 組み込みの基本的な型から , あるいは るための一時的なオプジェクトが新しく作成される。 基本的な型へ , 自動的かっ強制的に変換することを 次にこのオプジェクトと a とが加算されて , ほかの一 許す型変換関数を持っている ( たとえば ,String から 時オプジェクトが作られ , それが c にコヒ。ーされたあ char * , char * から String, lnteger から long int, と , 両方の一時オプジェクトが消去される。いい換 longint から lnteger など )。よきにつけ悪きにつけ , えれば , このコードは lnteger a, b, c ; プログラマが特別な注意を払っていないところて、 , tl 十 = b ; lnteger t2(tI) ・ teger tl(a) ・ このような循環的な型変換関数が組み込み型からあ 2 十 = a; c = t2; と等価な効果を持つ。 るクラスの関数を経由して元の組み込み型に変換を 小規模なオプジェクトや単純な演算子 , そして時 行うことがありうるために このような型変換関数 間やメモリ容量にこだわる必要のないプログラムの には賛否両論がある ( * 10 ) 場合には , 一時オプジェクトの作成は大きな間題て、 さらに , これらのクラスのうちのほとんどにおい はない。しかし , プログラムを微調整しているとき て , 表現に依存しない演算がコンストラクタなして、 には , しばしばこラしたコードを読みやすくはなく 行えるように , 基本的な型とクラス型とを組み合わ てもより効率的なものに書き直すことはよい考えて、 せて使う演算子や関数が用意されている。たとえば , あるといえることもある。 String と char との連結専用の連結演算子があるが , int や float のような組み込み型に関しては , れは結果が String のヘッダにしか依存しないためて、あ た式をどう最適化すれば一時オプジェクトの必要性 る。前述したように こうした設計にも賛否両論が を減らせるか , ということを C あるいは C 十十コンパ ある。これら各ケースをサポートするために関数が * 10 これらの関数は , C の イラが知っている。しかし不幸にも C 十十ユーザ定義 かなりの量に ( 主としてインラインて、あるが ) 増加し 関数のイ吏用を考えた場合 , 型に関してはそうて、はない。その理由は簡単なこと ているが , その結果効率的な演算が得られるのて、あ とくに必要て、ある。ただ , String 型と char* の関係 ( しかし現在の文脈て、は非常に困ったことて、あるが ) る。クラスを作る目的の一部としてプログラマが下 を考えても , これがやっか いて、あることは間違いない て、 , 多重定義演算子の意味あるいはそれらの相互関 層の表現を操作したり迂回したりする気にならない だろう。というのも , String 係については何ら保証されていないからて、ある。た から char * による変換の結 ために十分な機能と効率を持っということがあるゆ 果のポインタはどの領域の とえば , 前記の式に含まれている変数が lnteger て、は こて、は効率が節約に優っているといえる。 ポインタてあるかというこ とて、ある。 String の内部表 なく int て、あったならばコンパイラは内部て、このステ 式に向いているクラスを 現へのポインタか , String ートメントを c 十 = a ; c 十 = b ; c 十 = a ; の の中身の複製へのポインタ 使うためのガイドライン かなどだ。前者は String の ようなもの , あるいはさらに賢いコードに変換する 僻欟冓の未をなくすか もしれない。あるいは内部 C 十十て、はユーザ定義のクラスのために演算子を多 て、あろう。しかし , C 十十は lnteger の演算子十 = が 表現が char* ほど単屯ごな 重定義することが許されるのて、コ nteger や String な lnteger の演算子十とどのような関係にあるのか , と いかもしれない。後者て、は 私たちが通常考える型変換 どのようなライプラリクラスを用いたプログラミン いうことを知らないのて、 , C 十十コンパイラはこの種 の未と違う結果になる。 グが非常に快適に行える。しかし , それらの演算子 の式最適化を自分自身て、行うことがて、きないのてあ * 11 ここて述べられたよ うな最適化を C 十十て、うま に固有の限界や問題点についてはよく知っておくと る ( * 11) くやるガ去は幾度となく提 代入演算子は一時オプジェクトの作成をしないの 案されている。ここて、 lnte ger operator 十十 ( ln 多くの演算子は暗黙のうちにコンストラクタを使 て、 , 多くの場合において , プログラマは可能ならば teger&, lnteger&, lnteger&) : という演算子 用する。すなわち , たとえばある引数を持ったある いって、も代入演算子を使うことによって一時オプジ が定 ( 、きればどうだろう 関数に基づいて新しいオプジェクトを作成する。と ェクトの作成を簡単に回避することがて、きる。しか 特集 C 十 + クラスライプラリ概論 75
し , て、きるだけ融通が利くように ほとんどのクラ スが、、はめこみアセンプリコード〃手続きを持ってい る。これによってプログラマは時間的 , 空間的 , そ して評価のストラテジを完全にコントロールするこ とがてきるようになる。この手続きはほとんどの場 合 , ふたつの const のソース引数とひとつのデスティ ネーション引数とを持った、、 3 ーアドレス〃手続きと呼 ばれるものて、ある。この手続きは適当な動作を行っ たあと , 結果をデスティネーションに書き込む ( 古い 値の上に重ね書きされることもあり得る ) 。手続きは 高速て、安全て、あるように設計されている。とくに 別名参照は常に正しくなされるため , たとえば add (), x, x) ; などというコードも完全にうまく働く ( これらの手続きの名前はクラスといっしょに並べら れている ) 。 たとえば ,lnteger の式 a = (b ー a) * -(d / c) ; を考えてみる。この式は以下のようにコンパイルさ ように自分て、直すことがて、きる。 しかし , 手動による賢い最適化によって , 以下の t3 = -t2 ; lnteger t4=tI * t3 ; lnteger tl=b-a ; lnteger t2=d/c ; lnteger れる。 a=t4 ; 76 C MAGAZINE 1992 7 用するよりはるかに明解て、ある。コードを正しく動 演算子は非常に快適て、あり , 手続き的なコードを使 ガイドラインの最後に付け加えておく。多重定義 ることがて、きる。 return ; } とす er&a) return r(a) { 「十 = a , 必要はない。上記の例て、は , lntegerf(constlnteg にインスタンスを作成し , 戻り値としてコヒ。ーする 作することを許す。したがって , 関数内部て、局所的 名前つき戻り値は , 返されたオプジェクトを直接操 戻り値 (named return value) を使用する方法がある。 ーされなければならない。 GNU C 十十て、は名前つき 出した側が使えるようになる前に関数の外部にコビ 様なムダなコビーを作ることになる。戻り値 r は呼び この関数が ( a f(a) ; のように ) 呼ばれると , 同 「十 = a ; retu 「 n 「 a lnteger f(const lnteger&a) { lnteger 「 を書くとしよう。 成して返す関数を作るときにも生じる。以下の関数 これに関連した現象はある型のインスタンスを作 作するようにし , 正しいことを確認したそのあとで 式の形式のコードを手続き的なコードに直して高速 化を図るのはよいことて、あるといえる。 擬似インデックス (pseudo-indexes) 便利なクラスには要素のコンテナとして動作する ものが多い。コンテナからこれらの要素をアクセス するテクニックはクラスによってさまざまて、ある。 GNU C 十十ライプラリて、は , Pix と呼ばれる擬似イ ンデックスを使うことによってクラス間のアクセス メソッドが部分的にて、はあるが標準化されている。 Pix の働きは , あるいはインデックスのようて、もあ り , あるいはポインタのようて、もある ( 内部的にはた だの void * ポインタて、ある ) 。 Pix はクラスによって 要素へのアクセスに翻訳される一種の「キー」て、ある。 実際には P ⅸは何らかの内部記憶セルへのポインタて、、 ある。コンテナは要素を取り出す際にこのポインタ を使用する。 ューザは Pix の要素の集まりを巡回したり閲覧した りする際に配列のインデックスと同様の方法を用い ることがて、きる。しかし , P ⅸは 0 が不適切なものとし て扱われているという点においてポインタに類似し ており , プログラマが値の妥当性を確認せずに不適 切な Pix を使用して存在しない要素にアクセスしよう とする場合がある , というかぎりて、は安全なものと はいえない 一般的にいえば , コンテナへの破壊的な変更を行 っている最中に巡回を行うのは決してよいことて、は ない。典型的な応用例は以下のイディオムを用いた コードて、あろう。 a. first( ) ・ fo 「 (Pix i use(a(i)) ・ 0 ; a. next(i)) このコードはあるコンテナ a と関数 use のためのコ ードて、ある。 Pix による使用をサポートしているクラスは常に以 こて、はコン 下のメソッドを持っている。ただし , テナ a は型 Base の要素を持つものとする。 a. first ( ) ・ Pix i i が a の最初の要素を指示するようにする。コン テナが空ならば 0 を代入する。 ・ a. next(i)
Fig. 3 C の標準ライプラリ関数 sp を呼び出すプログラム [PascaI 部分ソース (SQ. PAS)] rogram sq L c sqrt} function call—sqrt(): double) : double; external ; var a: double; beg i n a ド 511 ー sqrt ( 2. の ; writeln(' sqrt(). の end. [ アセンプラ部分ソース ( C ー SQRT. ASM ) ] I DEAL MODEL TPASCAL DATASEG CODESEG EXTRN C sqrt:NEAR ; C 形式で sqrt を呼び出す 数学関数は matherr を参照している ( ここではがにもしない ) PUBLIC matherr PROC C _matherr NEAR ARG why : WORD, funcname : WORD, argl : WORD, arg2 : WORD, retva 1 : QWORD ・ nothing fldz , return 0.0 ret Fig. 1 PXENGINE. PAS の追加テータ (837 行目 :implementation の直前 ) { あいまい検索 } function PXSetSrchAimai( Aimai : lnteger) : lnteger; functi on PXA ima i Srched ( var IsAimai : lnteger) : lnteger; ( 916 行目 : end. の直前 ) function PXSetSrchAimai ; external ' PXENGWIN' index 104 ; function PXAimaiSrched; external ' PXENGWIN' index 105 ; Fig. 2 間接的に C の標準ライプラリ関数を呼び出すプログラム CPascal 部分ソース (EQUIP. PAS)]] program equ 1 L c—pc98eq L pc98eqip function call—pc98equip: WORD; external ; var : WORD; begin eq : ニ call—pc98equip; write(' system clock: ' ) ; if ()q and $ 08 ) く > 0 then writeln('8MHz' ) else writeln(' 5MHz' ) ・ write(' resolution: if ( and $ 800 の◇ 6 then writeln(' high' ) else writeln('normal' ) ; end. ENDP PUBLIC PROC cal l_sqrt call—sqrt NEAR ; QWORD(double) 型の引数をとる val :QWORD Cval] ; 引数をコプロセッサのスタックに取得 CQIORD vrR bp-8] , ・引数をそのままスタックに転送する ; s rt の呼び出し sqrt り値はコプロセッサのスタックに sp, 8 ; 返されるので、そのまま戻る ; C で浮動小数演算を使うプログラムから ; 必ず参照されるシンボル名 ARG fld sub fstp fwait call add ret [ アセンプラ部分ソース ( C ー PC98EQ. ASM ) ] I DEAL MODEL TPASCAL CODESEG EXTRN C pc98equip:NEAR ; C 形式で pc98equip を呼び出す ; PASCAL 形式の関数定義 PUBLIC call_pc98equip PROC call_pc98equip NEAR call pc98equip ret ENDP PUBLI C TURBOFLOAT PROC TURBOFLOAT ENDP END [ SQRT. OBJ の作成手順 ] TLIB MATHS *SQRT るプログラムは , そのヘルバルー クすることはて、きません。 チンカ℃のライプラリ関数にしかな ※プログラミングに関する一般的 いため , Turbo Pascal て、はリンク なご質問は , マスタディスク中の がて、きます。 sqrt を呼び出すプログラムを Fig. 3 て、きなくなります。結果的には , HELPME ! . DOC にも記載されて 浮動小数演算を使っているモジ に示します。 Turbo Pascal のためのモジュール おります。テクニカルサポートセ 実際には , Turbo Pascal と Tur ュールについては , 数学関数を使 は最初から Turbo Pascal 用に書き ンターて、は個々のプログラムに関 boC 十十 / BorlandC 十十のやりと 直してしまうのが効率よく安全な わない簡単なものて、あれば可能な するアドバイスやデバッグについ りにはアセンプラに関するかなり 手段だといえます。 こともありますが , 数学関数を使 ては承っておりませんのて、 , 個々 詳しい知識が必要となります。ま っている場合は , 8087 や turboF なお , Turbo Pascal には . OBJ の問題についてはマニュアル , RE た , そうした点について注意して loat などのグローバル変数が使われ 形式のファイルを作成する機能が ADME, HELPME ! . DOC などを もなお数々の制約が残ります。例 るため非常に難しくなります。上 ないため C / C 十十のプログラムから 参考にしてください 己の方法て、 C の標準ライプラリ関数 えば , C て、 ng 型の乗算を行ってい Turbo Pascal のモジュールをリン ENDP EN D [ PC98EQ 旧 . OBJ の作成手順 ] TLIB CS *PC98EQIP 三一口 lnformation from Compiler Makers 167
最近では dJgpp なとにより MS - DOS マシンて も GNLJ C 十十か使える。ここては , GNIJ C 十十 付属ライプラリであるⅱ bg 十十を , そのマニュア ルてある『 LJse 「 'sGuidet0GNLJ C 十十 L ib 「 a 「 Y 』の翻訳を中心に紹介する。 GNU C 十十ライプラリマニュア丿レ 村山孝夫 GNUC 十十ライプラリ ( libg 十十 ) は , D UNIX の curses ライプラリをクラスにまと 32 , 48 ビットの精度 ) 。 めたもの。この curses ライプラリとは , 各 ougLea 氏らにより開発された GNUC 十十 Bits プログラムが煩わしい端末制御の多くを のためのクラスライプラリて、 , FSF (Free S 0 か 1 のデータを扱うために BitSet と BitS 行わなくてもよいように , 端末制御のた tring がある。 BitSet は , 0 か 1 のデータの oftware Foundation lnc. ) 社の配付する GN めの機能をライプラリにしたもの。 U C 十十に含まれている。またライプラリ 集合を扱うものて、 , BitString は , 0 か 1 の またこのほかに genclass ユーティリティを にはクラスライプラリだけて、はなく , 列を扱うもの。 使うジェネリッククラスがいくつかある。 つかユーティリテイも含まれている。 String このジェネリッククラスとしては , List, L 本特集の他章て、触れたクラスライプラリ 文字列型。 char* の代わりに fprintf, St rcmp などの引数に使える。また , 正規表 inkedList, Vector, PIex, Stack, Queu の多くは , あるひとつのクラスを根とする 階層構造を持っていた。しかし本章て、触れ 現のためのクラス Regex もある。 e, Deque, PQ, Set, Bag, Map がある。 詳しくは本誌 1992 年 5 号の「 djgcc 詳解講座」 る libg 十十は , 設計の違いから階層構造を持 Random を参照されたい これは乱数生成のために使用される。乱 っていない。つまり , libg 十十のクラスは , 数生成と乱数分散のアルゴリズムは , 用 GNUC 十十ライプラリに付属する fI_Jse それぞれ独立したクラスて、あり , libg 十十は r' s Guide 』 (Fig. 21 参照 ) の翻訳を掲載す 意されているいくつかの中から選択する それらが単に集まったものて、 , それらクラ ことが可能て、ある。 る。ただ , 誌面の関係から , 本章に掲載す スの間にとくに関係はない。 Fig. 20 におも るのは冒頭部分だけて、ある。残りは , 本誌 Data なクラスをあげる。 連載「 djgcc 詳解講座」て掲載していく予定て、 データの集まりを分析するためのクラス lnteger ある。 として SampleStatistic と SampleHistogr 整数を扱うためのデータ型。 C の int などと GNUC と GNUC 十十は Ver. 2.0 から C , am がある。 SampIeStatistic は , double 型 違って扱う数値にとくに制限はない のデータを収集し , 統計を求めることが C 十十 , ObjectiveC の三つの言語を統合し RationaI ている。ライプラリも 2.0 になった。ただ て、き , SampIeHistogram は , Histogram 有理数を扱うためのデータ型。この型は こて、は , 2.0 の GNUC 十十ライプラ を出力することがて、きる。 1 / 3 のように小数として割り切れない数値 し , リて、はなく 1.39 の解説を行った。したがっ を扱える。 C の FILE 構造体の C 十十バ て , ここて、掲載する GNU C 十十ライプラリ Complex ーション。ファ イルに対する基本操作が用意されている AT&T のクラス complex ( 複素数 ) と同等 の User' s Guide の翻訳も 1.39 て、ある。 ( 翻訳参照 ) 。 の機能を実装したもの。 本章にかぎって , GNUC 十十 Libr stream AT&T の iostream ライプラリと機能上同 ary General Public License にもとづ [ ー 1 , 1 ) の範囲の実数を扱うデータ型。 じものを実装したもの ( 翻訳参照 ) 。 いた再配布を認めます。 実際には四つのクラス Fix, Fix16, Fix CursesWindow 24 , Fix32, Fix48 がある ( それぞれ 16 , 24 , 70 C MAGAZINE 1992 7
なイーハヘッドかめる階層構造は意味がな この理由は , C 十十の厳しい型検査を考え 数個のクラスから始められ , ほかのクラス たプログラミングて、はなく , 基底クラスの をあまり気にせず拡張て、きる , 非階層構造 このようにどちらの構造がとくに優れて ポインタと仮想関数を使った動的型決定メ のほうが実装も簡単て、ある。また , オプジ いる , というわけて、はない。どちらを選択 カニズムによるプログラミングを行うため ェクト指向プログラミングなどをあまり考 するかは , ライプラリをどういうことを対 て、ある。 えず , クラスを抽象データ型としてだけ使 象に設計するかによる。 このプログラミングを可能にするために うのて、あれば , 仮想関数などによってムダ この階層構造と非階層構造の もちろん , は , このような継承による階層構造を持っ 必要がある。たとえば , OODBMS( オプジ Fig. 1 N 旧 CL クラスライプラリの階層構造 ェクト指向データベース管理システム ) て、複 N 旧 CL—Object Collection OrderedCltn—SortedCItn—KeySortCItn SetCltn Random ArrayOb Stack 数の型のオプジェクトを扱う場合 , 非階層 FDSet A 「「 aycha 「 LinkedList 構造なら各クラスは型の識別のための情報 lnterator Heap を持ち , プログラムを扱う型すべてを意識 Class Dictionary ldentDic したコードて、ある必要がある。 ldentSet しかし , それらがひとつの基底クラスか Vecto 「 らの派生クラスて、あれば , readFrom と sto Rectangle Point reOn などという仮想関数て、解決てき ( 米 var Bitset sant 社の OODBMS には NIHCL が組み込ま lnteger れている ) , インタフェイスも基底クラスて、 Float 定義することて、統一て、きる。 List 1 にコード Fraction の例を示す。ひとつの基底クラスからの階 Time Date 層構造て、なければ , こう簡単には書けない だろう。 UI のライプラリて、も , この特徴は LookupKey Assoc 重要て、ある (InterViews や ET 十十などの UI Assoclnt のクラスライプラリは , ほばすべて階層構 Regex 造を持っ ) 。 Process StackProc ただ , デメリットがないわけて、はない LinkOb HeapProc この階層構造を C 十十て、使う場合 , 操作の多 くを基底クラスのポインタて、行うことにな る。当然 , いくつかのキャストが必要とさ れプログラムの中にバグを埋め込んてしま う可能性がある ( 関連の話題がパート 2 にも ある ) 。また , 仮想関数の多用はオーバヘッ ドを持つのて , 少して、はあるが速度が犠牲 になってしまう。 Bag S et DoubIeVec FloatVec LongVec lntVec ShortVec B yteVec BitVec String Link ShardQuence Semaphore Scheduler List / / クラス宜言は省略 int main() { / / クラス階層の基底クラス 0bject へのポインタを格納する辞書 Dict を使う . Dict く 0bject* 〉 dict; 〃ファイル bar をデータファイルとして使う . File f( ” bar ” ): / / この辺で dict に要素をいれる . 〃辞書 Dict の要素を順番にデータファイルに格納する . fo 「 (0bject* i = dict. first(); i , i ニ dict. next) { / / 要素の型を考える必要はない . クラス階層構造のクラスであれば , / / 仮想関数 st 。 re0n がうまくやってくれる . i->storeOn(f) return 1 ; 一 1- り 0 00 -4 戸 0 6 ー 8 9 0 1 より介 0 -4 0 6 「ー 8 9 0 ー 1 よ 1 よ 1 よ 1 ・一 1 ↓ 14 1 ↓一 1 よ 1 よっな 非階層構造 また , 階層構造を持たないライプラリも いくつか存在する。この構造は , ライプラ リの各クラスが継承関係を持たず , C の int や char のように独立したデータ型が横に並ん だものて、ある。 この構造が選ばれる理由としては , 実装 のやりやすさと速度があげられる。当殀 48 C MAGAZINE 1 2 7
0 K ( ) と名前づけられたメソッドが用意されている。 これはクラスの演算が正しくなされているかどうか の点検を手助けするものとして有用て、ある。 OK ( ) の実行により , クラスオプジェクトの、、表現 の不変性クがチェックされる。すなわち , OK ( ) の実 行とはオプジェクトが妥当な状態にあるかどうかの 検査て、ある。要するに , ①クラスの演算によって常にオプジェクトが妥当な 状態を維持していること ②呼び出し元の関数がこの状態を破壊することがて、 きないようにクラス自体が保護されていること というライプラリの約束が守られていることを ( とき には部分的に ) 確認する , ということて、ある。 妥当性を確認するための単純な技法て、は , あらゆ る操作が正しく行われていることは保証て、きないが , OK ( ) の呼び出しによって , 少なくとも演算によって 誤った表現が作り出されてはいないことは確認て、き たとえば , String a, b, c ; というコードにおいて , a. 0 K ( ) ; は a が妥当な Strin g て、あることを保証するが , その中身が b 十 c という連 結の結果て、あることは保証してくれない。しかし , a が妥当て、あることが判明すれば , その中身につ c & & a. before(c) いて , たとえば a. a 升 e 「 ( b ) b によって , さらに検査を進められる。換言す れば , 0 K ( ) は , 一般に , ューザがアクセスて、きない ようなクラスの内部表現そのもののみをチェックす るのて、ある。さらに妥当性を検査するためには , ほ かの演算が利用されることが多い OK ( ) の呼び出しに失敗した場合 , そのクラスが e 「「 0 「メソッドを持っていればそれが呼び出され , なけ れば abo が直接呼び出される。 OK ( ) 呼び出しの失敗は , 報告されるべき実装工ラ ーがあることを示している。 まれに例外があるものの , クラスの内部て、サポー トされている関数が自ら 0 K ( ) を呼び出すことはまっ たくないといってよい ( しかし , 配布されたテストフ ァイルの多くはよく OK ( ) を呼び出している ) 。 複雑なデータ構造に対して表現の不変性の検査を 行うと , 非常に時間がかかることがある。 74 C MAGAZINE 1992 7 可変サイズのオプジェクトを 表現する方法 GNU C 十十ライプラリを使用する目的のひとつに は , ( ほば ) 、、組み込みのクラスとして ' ℃十十に含まれ ると考えられるような基本クラスの種類を豊富にす ることがある。型を豊富に持っているほかの衄 「コロロ とりわけ Common Lisp と Scheme との特徴から , 多 くの示唆が得られた。ライプラリ中のクラスとその フレンドの演算子および関数のほとんどは , これら の言語の影響を大きく受けている。 こうして作成された 4 種類の型 , すなわち string, lnteger, Bitset, BitString とそれらに関連する , あ るいはそれらから派生した型は , 未使用領域上にあ る可変サイズのオプジェクトを管理しやすい表現を 持っ必要がある。これらすべての型て、使用されてい るテクニックは基本的には同一て、あるが , その詳細 に関しては , 必然的にさまざまな点て、クラスごとに 異なるものとなっている。 これらのオプジェクトを表現するための一般的ス トラテージは , まずヘッダ情報 ( たとえばオプジェク トのサイズ ) と領域の最後に可変サイズのデータ ( あ る種の配列 ) を持ったメモリ上の小領域を作成するこ とて、ある。一般にオプジェクトの最大サイズには , 安全のためアドレスづけ可能なすべてのメモリの大 きさより少々小さいくらいという制限がある。また 最小サイズにも限界があり , 非常に小さな領域が増 加して割り当てるべきメモリを浪費しないようにし てある。内部的には , 小領域は new 演算子の性能を 最大にするようなプロック単位て、作成される。 クラスの要素そのものは , この小領域へのポイン タて、しかない。クラスの演算のほとんどは , 対応す る表現について , 必要とされる演算を行うようなイ ンラインの、、翻訳〃関数を通じて行われる。しかし , コンストラクタと代入演算て、は , ポインタを利用す るのて、はなく , 表現そのものをコヒ。ーして行う。 これらのクラスを使った式や関数て、の一時的な領 域生成を減らす試みは行われていない。以前のバー ジョンのクラスのユーザは , 、、 Tmp" クラスと参照回 数のカウントがなくなったことに気がつくだろう。 これらのものがパフォーマンスを向上するケースも 確かにあるのだが , 一方て、これらがクラスの操作法
00 C 十十クラスライプラリ概論 トされていない。コレクションを走査する クラスとして lterator ( 反復子 ) が用意されて いる。コレクションを探索に使うクラスと して LookupKey がある。 extern "C" int open (... ) ・ ーサインタフェイス ( というようにリンケージ指定をすればよい 本特集て、取り上げたライプラリだけて、も 開発支援 のだが , いくつかのクラスライプラリて、は 非常に多種類のクラスが用意されている。 既存ライプラリへのインタフェイスをクラ 以下に多少強引て、はあるが , クラスを種類 テキスト端末からビットマップディスプ スとして用意している。 GNU C 十十ライプ レイの制御まて、非常にたくさんある。 X W 別にまとめてみた。 ラリて、は , stdio に対するクラス F ⅱ e が用意 indow System 上て、は Stanford の InterView 要素としての s, ET 十十 , MS-Windows 上て、は Zincp ln されれている。 テータ構造の実装 terface Library ( ノヾ ート 2 参照 ) , WIN 十十 , C には int や char というデータ型があるが , C 十十 /Views, テキストて、は Object Profe このデータ型を拡張したものて、 , GNUC 十十 ssional for C 十十などが有名て、ある。これ このほかにもスマートボインタという , ライプラリや NIHCL て、は , 整数 (lnteger), らのライプラリには , Window の生成 , 消 メモリアクセス時に追加の処理を行うポイ 複素数 (Complex) , 行列 (Matrix) , 文字列 去 , 位置の指定 , ボタン , スクロールバー , ンタがある。多くのものは , ポインタによ (String) , 日付 (Date) , 時刻 (Time) などが ダイアログなどという Window 制御のほか るアクセスの前後て、 , ポインタが正しく記 に , グラフィックの要素としての Point, L ある。 憶領域を指しているかどうかを検査するも たとえば , String て、は , C 標準ライプラリ ine, Rect などもある。 のて、ある。 この実例としてはパート 1 の Windows プロ の string. h て、与えられている strcmp や strca t に加えて , 正規表現 regex を使った表現 もちろん , ほしいクラスの仕様にびった グラミングとパート 2 の ZIL の例を参照して ( 、 [A-Z] * [ 0 ー 9 ] ? " など ) や + , ーなどの演 りとうまくあうものがあることが望ましい いただきたい が , これだけあれば , びったりとはあわな くとも近いものがみつかるだろう。 ンテナとして テータ構造の実 どちらもを含んて、いるライプラリもある ( パ ート 2 の T001S. h 十十など ) 。 C ライフラリへの インタフェイ C 十十から C のライプラリ関数を呼び出す クフ冖ララリの内合 そのほか 数値演算 数値演算に FORTRAN の代わりに C 十十 を使うことは多いようて、ある。 C 十十の数値 辞書やスタックというようなほかのクラ スを要素に持っコンテナクラスて、ある。 演算ライプラリについても comp. lang. c 十十 最後に , クラスライプラリのもうひとつ て、はなく comp. lang. fortran て、議論されてい のようなクラスは , いままて、は generic. h を の使い道をあげておく。運よく , C 十十のク ることが多いようて、ある。 使って実装していたが , AT&T C 十十 3.0 ラスライプラリはソースコードて、与えられ からはテンプレートを使ってスマートに実 ート 2 て、は , 数値計算の市販のクラスラ ることが多い。このコードは , C 十十の優れ イプラリ Math. h 十十に関する解説がある。 装て、きるようになっている。 ほかにライプラリとして Matrix. h 十十 , Li た教科書て、ある 01nterViews や NIHCL から この種のクラスが豊富な GNUC 十十ライ C 十十の知識を得ている人も少なくないだろ プラリて、は , List ( リスト ),Vector( べクタ ), npack. h 十十 , M 十十 , また GNUC 十十ラ う。とくに C 十十のバイプルともいうべき fT stack( スタック ), Queue( キュー), Set' イプラリにはデータ統計のためのクラス Sa Map( 集合 ), Map ( 連想配列 ) などがある。 HE ANNOTATED C 十十 REFERENCE mpleStatistic や SampIeHistogram がある。 MANUAL 』 ( 通称 ARM) やの fThe C 十十 が豊富て、ある。コレクションとして , Colle Programming Language Second Ed. 』て、 ction, SetCltn, OrderedCltn, SortedClt も得られない実践上のテクニックが , クラ n, KeySortCltn, Stack, LinkedList, H スライプラリのソースコードには豊富に存 コルーチンスタイルのプログラミングの ために , AT & T の C 十十には task ライプラ 在している。 eap, ArrayOb, Arraychar, Bag, Dicti0 読者がクラスライプラリを有効に活用し , リが , NIHCL には Process, Scheduler, S nary, IdentDic , ldentSet, Set がある。階 C 十十プログラミングをエンジョイすること 層構造は Fig. 1 を参照してほしい。 Ordere emaphore が用意されている。 を期待する。 dCItn の階層下のクラスはソートされてい 教科 ルーチ、 特集 c + + クラスライプラリ概論 49
00 C 十十クラスライプラリ概論 まな開発段階にあり , 今後 GNUlibc ライプラリがリ リースされるときに実装の変更が施されることにな るだろう。 libg 十十て、サポートされているクラスの 2 番目のも のとして , 未使用領域上に置く可変サイズのオプジ ェクトをたやすく管理するための汎用の基本クラス がある。具体的には , Obstacks, 多精度の lnteger, RationaIs, 任意の長さを認める Strings BitSets それに BitStrings などがある。 3 番目に , 普通あったほうがよいと思われるような クラスがいくつかある ( たとえば Complex クラス ) 。 最後に , 共通のコンテナクラス (container classe s ) を作成するための機構として , 擬似ジェネリックな プロトタイプを利用することがて、きる。それらはコ ンテナプロトタイプの導入のところて、さらに詳しい 説明がされている。現在のところ , ・ジェネリックな クラスを作成するためには , テキスト上の置換を行 うしか方法がない ( * 6 ) GNU C 十十ライプラリの スタイルに関する習慣 ・ C 十十のソースファイルの拡張子は . cc て、ある。 C コンノヾチプルなヘッダファイルおよびクラスの宣 言を記述したファイルの拡張子はどちらも . h を使 用する ( * 7 ) 。 ・ C 十十のクラスの名前は大文字て、始める。ただし , istream と ostream に関しては , AT&T C 十十と の互換性を保持するために , このままとする。ク ラスの名前が複合語て、あるときは , 各語を大文字 て、始め ( * 8 ) , アンダースコアて、区切ることはしない ・ C 十十のクラスを定義するインクルードファイルの 名前は , クラスの名前と同様に , 大文字から始め る。 stream. h に関しては , やはり AT&T C 十十と の互換性を考慮して大文字にはしない ・システムコールやライプラリのような C の関数のプ ロトタイプ宣言を記述したインクルードファイル の名前は , すべて小文字て、書く。 ・ファイルの名前が X て、あるインクルードファイル は , 必ず X h というプリプロセッサ変数を定義 し , またこの変数がまだ定義されていない場合に のみ条件コンパイルする。 #pragma once もまた , 2 回以上インクルードするのを避けるために用いる ことがて、きる。 ・定義する際に公開しなければならないが , どこか らても使用て、きるようにするわけて、はない , う構造体やオプジェクトの名前はアンダースコア て、始める ( たとえば , String および SubString クラ ス内て、のみ使用されている S 「 ep 構造体がそうした 例て、ある ) 。 ・アンダースコアは , 長い関数名て、各語を分けるた めに使用される ( たとえば , set File exception h andler( ) ) 。 ・関数がメンバ関数としてもフレンド関数としても 定義て、きるときには ( * 9 ) , その関数が自分自身を変 更したり , あるいは自分自身を返したり , さらに はその両方て、あるような場合には , 一般的にはメ ンバ関数として定義し , これらの条件のいすれも 満たしていないならば , その関数はフレンドとさ こうした規則性 れる。ただし , 場合によっては , よりも表現としての自然さが優先されるときもある。 ・クラスを宣言しているファイルは , 関数の名前や パラメータなどを調べる際にすばやく確認て、きる ような書式が使用される。クラス宣言中に出現す るものはそれぞれ異なるのて、このような書式化に は完璧な方法があるわけて、はない。各クラス宣言 の書式スタイル共通化についての提案を歓迎する。 ・各クラスは同一の単純なエラー ( 例外 ) ハンドリン グストラテジを使用する。ほとんどすべてのクラ スが error(char* msg) という名前のメンバ関数 を持っており , これが関連するエラーハンドラ関 数を呼ぶ工ラーハンドラ関数の呼び出しはポイ ンタを通して行われるから , プログラマはこれを 独自の関数て、置き換えることがて、きる。デフォル トの関数としては , ほばすべてのクラスて、 * lib e 「「 or hand 厄「が呼び出される。この関数はメッセー ジを表示して実行を停止する。ただし , この手順 は変更されることがあり得る。一般に , 工ラーは 回復て、きないものと仮定される。ライプラリのク ラスは例外処理後うまく続行することを認めるよ ほとんどの GNU C 十十ライプラリのクラスには , サポート 表現の不変性に関する うなコードにはなっていない * 5 InterViews も , Turb 0 C 十十付属あるいは MS- C 十十付属のクラスライプラ リも階層構造を持つ。 * 6 AT&T 3.8 ) テンプ レート機能により , もうプ リプロセッサや sed によるテ キスト置換に頼る必要はな くなった。テンプレートは ANSI C 十十て、すて、に草案 が受理されている。 * 7 AT&T C 十十て、は , C 十十ソースファイル窈広張 子は標準て、は . c と . C て、ある が , ほかに . cpp や . cxx カイ吏 われることもある。 * 8 MS ー DOS のファイル 名の制約から , ファイル名 の最初の文字を大文字にす る代わりにアンダースコア を使う。 String. h て、あれ ば , 代わりに STRING. H が使われる。 * 9 メン数とフレンド 関数の使い分けは , 時と場 合による。気をつけるべき ことのひとつに , メンバ 数は継承されるが , フレン ド関数は継承されないとい う点がある。たた購文上の ことを考えれば , フレンド のほうが優れているといえ る。たとえば , クラス X のフ レンドとメンバを考えると , フレンドてあれば , X は第 2 引数の型て、あってもよいが , メンヾては ( 暗黙の ) 第 1 引数 の型て、ある必要がある。 のことはとくに中置表記の 演算子て、は未がある。フ レンドてあれ灯 int 型 ) 十 ( X 型 ) が許されるが , メンバて、 あれば , int から X への型変 換 ( コンストラクタ ) があった としても許されない。メン バの場合 , 暗黙の第 1 引数は 厳密にそのメンバの型てあ る必要がある。 特集 C + + クラスライプラリ概論 73
00 C 十十クラスライプラリ概論 Fig. 20 GNU c 十十クラスライプラリのクラス ・ Pix ・・・・・・疑似インテックス ファイル操作 ・ File, SFile, PlotFile, Filebuf ・ストリームクラス ・ istream, ostream ・ Obstack ・・・・・・オプジェクトスタッククラス 時的にオプジェクトを保管しておく場所 ・ AIIocRing ・ String, Substring ・ " " ・文字列クラス ・・正規表現クラス ・ Regex ・ ・ lntege 「・ ・ Rational ・ ・ Complex ・ ・・多精度の整数クラス ・・多精度有理数クラス 複素数クラス ・ Fix1 6 , F ⅸ 24 , Fix32, F ⅸ 48 ・・・・・・固定精度クラス ・ビットテータを扱うクラス ・ BitSet, BitSet32, BitSet256, BitString ・ ・ RNG, Random ・・・・・・乱数生成クラス ・ ACG, MLCG, Binomial, Erlang, Geometric, HyperGeometric, NegativeExpntl, NO 「 mal, LogNormaI, Poisson, DiscreteUniform, Uniform, WeibuII, RandomInteger ・ ・ SampleStatistic, SampleHistogram ・・・・・・標本統計やテータ収集に関連したクラス cu 「 ses ライプラリ実装クラス ・ CursesVVindow Lisp ライクなリストのクラスプロトタイプ ・ List ・ SLList ・・・・・・単方向リストのクラスプロトタイプ ・ DLList ・・・・・・双方向リストのクラスプロトタイプ ・・べクタクラスのプロトタイプ ・ Vec, AVec ・ インテックスの自由な配列クラスのプロトタイプ ・ Plex, FPlex, XPlex, RPlex, M Plex ・・スタッククラスのプロトタイプ ・ VStack, XPStack, SLStack ・ ・ VQueue, XPQueue, SLQueue ・・・・・・キュークラスのプロトタイプ ・ XPDeque, DLDeque ・・・・・・両方向キュークラスのプロトタイプ ヒープ ( 優先度つきキュー ) クラスのプロトタイプ ・ XPPQ, SPlayPQ, PHPQ ・・乱数分布クラス ・ XPSet, OXPSet, SLSet, OSLSet, AVLSet, BSTSet, SpIaySet, VHSet, VOHSet, CHSet " ・・・・集合クラスのプロトタイプ ・ XPBag, OXPBag, SLBag, OSLBag, SplayBag, VHBag, CHBag ・ ・・バッグクラスのプロトタイプ ・ GetOpt ・ ・ C 十十クラスの実装による GNU / UN Ⅸコマンドラインオプション解析関数 ・ AVLMap, RAVLMap, SpIayMap, VHMap, CHMap ・・・・・・連想配列クラスのプロトタイプ Fig. 21 「 User's Guide to GNU C 十十 Lib 「 ary 」のおもな目次 ・ GNU Library General public License ・ Contributors to GNU C 十十 library 14. ストリームクラス 13. ファイルクラス 1 . G N U C 十十ライプラリのインストール 2. インストールの際の問題点 3. GNU C 十十ライプラリのねらい , 目的と限界 9. 擬似インテックス 8. 式指向なクラスを使うためのガイドライン 7. 可変サイズのオプジェクトの表現方法 6. コンテナクラスプロトタイプの初歩 5. 表現の不変性に関するサポート 4. GNU C 十十ライプラリのスタイルに関する習慣 12. 動的割り当てのためのライプラリ基本関数 1 1 . 組み込み型の演算を行うユーティリティ関数 10. ヘッダファイルおよび c 十十から c へのインタフェイス 15. オプジェクトスタッククラス 16. 一時的にオプジェクトを保存しておく場所 17. 文字列と正規表現関係のクラス 18. 多精度の整数クラス 19. 多精度有理数クラス 20. 複素数クラス 21. 固定精度クラス 22. ピットテータを扱うクラス 23. 乱数生成クラスと各種乱数クラス 24. 標本統計やデータ収集に関連したクラス 25. Curses ライプラリ実装クラス 26. Lisp ライクなリストのクラスプロトタイプ 27. Linked クラス 28. Vecto 「クラス 特集 C + + クラスライプラリ概論 71 36. Map クラスの原型 35. Bag クラスの原型 34. 優先的 Queue クラスの原型 33. Set クラス 32. Double ended Queue クラス 31. Queue クラス 30. Stack クラス 29. 円 ex クラス
すべてのウインドウ構成部品は、、十〃オペレ ータを抽象べースクラス UI ELEMENT か ら継承している。ウインドウを構築するに は , まず UIW WINDOW のインスタンスを new し , それに対して外枠 , タイトル , ボタ ンなどを new しては、、十クオペレータて、貼り付 けることて、ウインドウが構築される。この ようにして作られたウインドウをウインド ウマネージャにヾ十〃し , イベントループを 回すことて、イベントの受理と配送が行われ , イベントに応じた画面が表示される。ウィ ンドウ構成部品が画面から消えるとき , そ の部品に、、 + 〃された構成部品は再帰的に de lete される。したがって , new された構成部 品をプログラマが明示的に delete することは 渡される。ウインドウマネージャはそのイ て受理され , ウインドウマネージャに引き てのイベントはイベントマネージャによっ アプリケーション実行中に発生するすべ ほとんどない 68 C MAGAZINE 1992 7 珍しい方法て、あるが , ボタンごとにたくさ る。これは GUI クラスライプラリのなかて、は それに従って処理を振り分けることがて、き からユーザ定義値を読み出すことがて、き , くと , コールバック関数側て、イベント引数 ユーサ、定義の unsigned short 値を設定してお また , コールバック関数の登録とともに ック関数を登録する方式を使うこともて、きる。 るほか , MS-Windows と同じくコールバ 装することによってもイベント処理がて、き ZIL て、は , 仮想関数 Event( ) を再定義 / 実 す。 ってアプリケーションにイベントを引き渡 イプラリて、は , 仮想関数の再定義 / 実装によ い。 Turbo Vision をはじめ多くのクラスラ したなんらかの処理を行わなければならな アプリケーションプログラムはそれに対応 たとえば , あるボタンが押されたとき , 送する。 I WINDOW OBJECT の派生クラス ) に配 によって対応するウインドウの構成要素 (U べントを仮想関数 Event ( ) をコールすること Fig. 18 刀 L クラス階層 UI—ELEMENT UIW—SCROLL—BAR UIW—PULL—DOWN—MENU UIW—POP—UP—MENU UIW—MATRIX UI—HELP—WINDOW—SYSTEM ULERROR—WINDOW—SYSTEM UIW—WINDOW UIW—TIME UIW—TEXT UIW—DATE UIW—STRING UIW—PROMPT UIW—REAL に5W 」 NTEGER UIW— N U M B E R UIW 」 CON UIW—FORMATTED—STRING UIW—TITLE UIW—SYSTEM—BUITON UIW—PULL—DOWN 」 TEM UIW—POP—UP 」 TEM UIW—MINIMIZE—BUTTON UIW—MA 刈 MIZE—BUTTON UIW—BUTTON UIW—BORDER UI—WINDOW—OBJECT UI—QUEUE—ELEMENT UI—JUMP—ELEMENT UI—MSWINDOWS—MESSAGE UI—MS—MOUSE UI—CURSOR UI—BIOS—KEYBOARD UI—DEVICE I—UI—HELP—WINDOW—SYSTEM UI—HELP—SYSTEM I—UI—ERROR—WINDOW—SYSTEM UI—ERROR—SYSTEM static void handle(v0id*,UI EVENT&) ・ N00dle() ・ 5 : public: UIW_STRING* message ・ 3 : class Noodle : public UIW—WINDOW { #include く ui win. hpp> ホタンイベントの処理 U I—TI M E U l— DATE UI—PATH UIW—WINDOW UI—WINDOW—MANAGER UI—STORAGE UI—MSWINDOWS—DISPLAY UI—DOS—TEXT—DISPLAY UI—DOS—FG—DISPLAY UI—DOS—BGI—DISPLAY L—UI—DISPLAY UI—REGION—LIST I—UI—QUEUE—BLOCK UI—LIST—BLOCK UI—JUMP—LIST UI—EVENT—MANAGER UI—LIST 16 : 14 : 13 : 12 : 11 : 9 : 7 : 6 : 4 : 2 : 1 : イベントテパイス キーボード カーソルコントロール マウス MS-Windows イベント 画面構成部品 外枠 ボタン 最大化ボタン 最小化ボタン ポップアップ要素 プルダウン要素 システムホタン タイトル フォーマットを指定した 1 行文字列 アイコン 数値 整数 実数 プロンプト 1 行文字列 日付 複数行にわたる文字列 時刻 ウインドウ 工ラーウインドウ ヘルプウインドウ 2 次元に配列された要素 ポップアップメニュー プルダウンメニュー 縦スクローラ 工ラーウインドウ ヘルプウインドウ イベントマネージャ ティスプレイドライバ Borland BGI ティスプレイ Zortech FG ティスプレイ DOS テキストティスプレイ MS-Windows ティスプレイ ウインドウマネージャ 10 : Noodle::N00dIe() : UIW_WINm)W(5, 5 , 30 , 9 , WOF_NO_FLAGS, WOAF_NO_SIZE) { *this + new UIW BORDER + new UIW-SYSTEM—BUTTON + new UIW—TITLE( ” Noodle") + new UIW_PROMPT(), 1 , "Which do you want to eat?") + new UIW_BUTTON(1,3, 11 , ” Spaghetti" BTF NO_TOGGLE IBTF_AUTO_SIZE, WOF_BORDERIWOF—JUSTIFY_CENTER, Nooäle::handle, の〃コールバック関数 handle を登録。ユーザ値 = 0 + new UIW_BUTTON(14, 3 , 11 , ” So ” ,