6.4 入出力ストリーム層の内部構造体

## 6.4 入出力ストリーム層の内部構造

先に説明したように、入出力ストリームは 2 層から成り、1 つは書式設定、残りはコード変換と、外部デバイスとの文字の移送に使用します。説明の都合上、図 20 の入出力ストリーム層を図 22 に再度示します。

#### 図 22 -- 入出力ストリーム層

以下の節では、クラスとその継承関係、個々の役割など、入出力ストリームのソフトウェアアーキテクチャーについて詳しく説明します。入出力ストリームをすぐ使用する場合は、第 7 章に進んでください。

### 6.4.1 書式設定層の内部構造

書式設定層に所属するクラスを、ストリームクラスと呼びます。図 23 はすべてのストリームクラスの階層を表したものです。

#### 図 23 -- 書式設定層の内部構造

『標準 C++ クラスライブラリ・リファレンス』では説明対象となっていますが、クラス `strstream`、`istrstream`、`ostrstream` はこの図にはありません。標準入出力ストリームで、陳腐化した機能とも呼ばれるこれらのクラスは、従来の入出力ストリームとの下位互換性を保つためにだけ残されています。したがって、標準入出力ストリームの将来のバージョンでサポートする予定はありません。

以下の節では、図 23 に示すクラス階層の構成要素と、その特性について詳しく説明します。

#### 6.4.1.1 入出力ストリーム基底クラス ios_base

このクラスは、すべてのストリームクラスの基底クラスです。文字型とは関係なく、すべてのストリームが必要とする、次のような情報をカプセル化しています。

- 構文解析と書式設定のための制御情報
- ユーザーの特別な要求に応じたその他の情報 (入出力ストリームを拡張する方法。後に説明します。)
- ストリームに組み込まれたロケール

また、ios_base では、書式フラグ、ステータスビット、オープンモード、例外クラスなどすべてのストリームクラスで使用する型を定義します。

#### 6.4.1.2 入出力ストリームの文字型 - 依存基底クラス

次に示すのは、ストリームクラスの仮想基底クラスです。

>     basic_ios<class charT, class traits=char_traits<charT> >

このクラスには、ストリームバッファに対するポインタと、ストリームバッファの完全性を示す状態情をおさめます。basic_ios<> は、ストリームで処理する文字型と文字の特性という 2 つのパラメータを使用するクラステンプレートです。

文字型には、1 バイト文字の型 `char` やワイド文字の型である `wchar_t`、または他のユーザー定義の文字型が含まれます。`char` と `wchar_t` には、標準 C++ ライブラリによるインスタンス化機能があります。

これらのインスタンス化には、利便性のために typedef が用意されています。

> ios 用の `typedef basic_ios<char>`
> wios 用の `typedef basic_ios<wchar_t>`

ios は従来の入出力ストリームの場合のようなクラスではありません。古い入出力ストリームを使用するプログラムが残っている場合、それらを新しい標準入出力ストリームに使用することはできません (第 24 章参照)。

#### 6.4.1.3 文字の特性

ここでは、文字型の属性を説明します。文字型では次のように多くの変更があります。

- ファイルの終わりを示す値。型 `char` の場合、ファイルの終わりは、`EOF` という整数定数で表します。型 `wchar_t` の場合、`WEOF` という定数があります。ユーザー定義の任意の文字型に対応する文字の特性で、それぞれのファイルの終わりの値を定義します。
- `EOF` の値の型。これは `EOF` の値に対応できる型にします。たとえば、1 バイト文字の場合、この型は `int` であり、実際の文字型 `char` とは異なります。
- 2 つの文字の等価性。海外のユーザー定義の文字型の場合、2 つの文字の等価性は、ビット式の等価性と同じではありません。ここでそれを定義します。

文字の特性の全リストについては、 『標準 C++ クラスライブラリ・リファレンス』の `char_traits` を参照してください。

型 `char` と `wchar_t` には、特殊クラスがあります。一般に、このクラステンプレートは文字型のインスタンス化を目的としたものではありません。常にクラステンプレートの特殊クラスを定義する必要があります。

標準 C++ ライブラリは、最も代表的な事例が最も簡単に処理できるよう作られています。文字特性で悩むことのないように、この特性テンプレートパラメータには実用的なデフォルト値が用意されています。

#### 6.4.1.4 入出力ストリーム

入出力には、次の 3 つのストリームクラスがあります。

>     basic_istream <class charT, class traits=char_traits<charT> >
>     basic_ostream <class charT, class traits=char_traits<charT> >
>     basic_iostream<class charT, class traits=char_traits<charT> >

クラス `istream` は入力を、クラス `ostream` は出力を処理します。クラス `iostream` は入力と出力を処理します。このようなストリームを双方向ストリームと呼びます。

3 つのストリームクラスでは、構文解析と書式設定の関数を定義します。これらは入力用の `operator>>()` のオーバーロードバージョンであり、抽出子といいます。出力用の `operator<<()` のオーバーロードバージョンを挿入子 といいます。

その他、書式設定のされていない入出力用には、`get()` や `put()` などのメンバー関数が用意されています。

#### 6.4.1.5 ファイルストリーム

ファイルストリームクラスは、次のように、ファイルに対する入出力をサポートします。

>     basic_ifstream<class charT, class traits=char_traits<charT> >
>     basic_ofstream<class charT, class traits=char_traits<charT> >
>     basic_fstream<class charT, class traits=char_traits<charT> >

C 関数の `fopen()` と `fclose()` と同様の、ファイルの開閉に使用する関数もあります。内部では ファイルバッファという特別なストリームバッファで、対応するファイルとの文字の移送を制御します。ファイルストリームの機能を図 24に示します。

#### 図 24 -- ファイル入出力

#### 6.4.1.6 文字列ストリーム

文字列ストリームクラスは、次のように、メモリー内入出力をサポートします。これはメモリーに保持される文字列の読み書きのことです。

>     basic_istringstream<class charT, class traits=char_traits<charT> >
>     basic_ostringstream<class charT, class traits=char_traits<charT> >
>     basic_stringstream<class charT, class traits=char_traits<charT> >

バッファとして使用する文字列の呼び出しと設定に使用する関数があります。内部的には特殊化されたストリームバッファを使用します。この場合、バッファと外部デバイスは同じになります。図 25 は、文字列ストリームクラスのはたらきを示したものです。

#### 図 25 -- メモリー内入出力

### 6.4.2 移送 (トランスポート) 層の内部構造

移送層のクラスは、ストリームバッファクラスとも呼びます。図 26 はすべてのストリームバッファクラスのクラス階層を示したものです。

#### 図 26 -- 移送層の階層

ストリームバッファクラスでは、外部デバイスとの文字の転送を行います。

#### 6.4.2.1 ストリームバッファ

このクラスは、抽象ストリームバッファになります。

>     basic_streambuf<class charT, class traits=char_traits<charT> >

ここには外部デバイスの情報はなく、2 つの仮想関数 `overflow()` と `underflow()` を定義して、実際の移送を行います。この 2 つの関数には、接続されている外部デバイスの特性に関する情報があります。これらは、ファイルバッファや文字列バッファなどの、具体ストリームバッファクラスによって上書きされます。

ストリームバッファクラスでは、2 つの文字シーケンスを管理します。get area は外部デバイスから読み取る入力シーケンスであり、put area はデバイスに書き込まれる出力シーケンスです。バッファから次の文字を移送する `sgetc(``)` などの関数もあります。これらの関数は、書式設定層が構文解析時に文字を受け取るときに呼び出すのが普通です。このため、次の文字をバッファに移送するための `sputc()` のような関数もあります。

ストリームバッファでもロケールオブジェクトを移送します。

#### 6.4.2.2 ファイルバッファ

ファイルバッファクラスは、ファイルとの入出力シーケンスに対応しています。ファイルバッファの形式は、次のとおりです。

>     basic_filebuf<class charT, class traits=char_traits<charT> >

ファイルバッファには、`open()` や `close()` のような関数があります。ファイルバッファクラスは、そのストリームバッファの基底クラスからロケールオブジェクトを継承します。外部文字符号から内部文字符号への変換は、ロケールのコード変換ファセットによって行われます。図 27 はファイルバッファのはたらきを示したものです。

#### 図 27 -- ファイルバッファによる文字コードの変換

#### 6.4.2.3 文字列ストリームバッファ

このクラスではメモリー内入出力を実装します。

>     basic_stringbuf<class charT, class traits=char_traits<charT> >

文字列バッファでは、内部バッファと外部デバイスは 1 つであり、同じものです。内部バッファは動的なので、書き込まれた文字すべての格納に必要であれば拡張されます。内部保持バッファのコピーを出力したり、文字列を内部バッファにコピーすることができます。

### 6.4.3 ストリームとストリームバッファの協調

基底クラス basic_ios<> は、ストリームバッファに対するポインタを保持します。ファイルストリームや文字列ストリームのような派生ストリームクラスには、ファイルや文字列バッファオブジェクトをおさめます。
基底クラスのストリームバッファポインタは、この埋め込みオブジェクトを参照します。このアーキテクチャーを図 28 に示します。

#### 図 28 -- 入力ファイルストリームにおけるファイルバッファのはたらき

書式設定されていない入出力の場合のように、ストリームバッファはストリームと関係なく使用することができます。ただし、ストリームには必ずストリームバッファが必要です。

### 6.4.4 ロケールと入出力ストリームの協調

基底クラス ios_base は、ロケールオブジェクト用です。派生ストリームクラスで定義される書式設定関数と構文解析関数では、このロケールの数値ファセットを使用します。

クラス basic_ios<charT> には、ストリームバッファに対するポインタをおさめます。このストリームバッファにはロケールオブジェクトもありますが、通常は、ストリームクラスの関数で使用する同じロケールオブジェクトのコピーです。ストリームバッファの入出力関数では、付属ロケールのコード変換ファセットを使用します。図 29 は、そのアーキテクチャーを示したものです。

#### 図 29 -- 入出力ファイルストリームにおけるロケールのはたらき

Copyright (c) 1998, Rogue Wave Software, Inc.
このマニュアルに関する誤りのご指摘やご質問は、電子メールにてお送りください。

OEM リリース, 1998 年 6 月