## 17.5 派生ストリームにおける RTTI 用の iword/pword の使用

前節では、所定の入出力演算に対して RTTI (実行時型識別) を利用し、各ストリームの型の特性に基づいて動作を行わせる方法について説明しました。

新しいスタイルのキャスト `dynamic_cast<>` として、RTTI が C++ 言語に導入される以前は、RTTI の代わりに `iword()、pword()、xalloc()` で問題を処理していました。28 前の例でも分かるように、動的キャストによる方法は、RTTI の代替法よりも明らかに優れているため、この古い手法については簡単に説明します。現在のコンパイラが新方式のキャストをサポートしていない場合は、従来の手法でも有効です。

従来の方法の基本的な考え方では、挿入子やマニピュレータ関数など、実行時の型の情報を必要とする、ストリームクラスとすべての関数とクラスは、次の 2 つの条件を満たすものとします。

- 補助記憶領域用の配列までのインデックス。すなわち RTTI がどこにあるのか。
- 関係者が必要とする型の識別の内容。すなわち何が必要なのか。

以下の例では、派生ストリームクラスは、補助記憶領域までのインデックスを予約しています。このインデックスは、派生ストリームクラスの静的データメンバーであり、派生ストリームクラスのすべてのオブジェクトを識別します。そのストリームの補助記憶領域の特定のスロットの内容には、`pword()` でアクセスすることができますが、各ストリームオブジェクトの `this` ポインタであるものとします。

次に、派生クラス `odatstream` の変更バージョンを示します。

>     template <class charT, class Traits=char_traits<charT> >
>     class odatstream : public basic_ostream <charT,Traits>
>     {
>     public:
>      static int xindex()                                          //1
>      {
>       static int inited = 0;
>       static int value = 0;
>       if (!inited)
>       {
>          value = xalloc();
>          inited++;
>       }
>       return value;
>      }

>      odatstream(basic_ostream<charT,Traits>& ostr,const char* fmt = "%x")
>      : basic_ostream<charT,Traits>(ostr.rdbuf())
>      {
>        pword(xindex()) = this;                                    //2

>        fmt_=new charT[strlen(fmt)];
>        use_facet<ctype<charT> >(ostr.getloc()).widen(fmt, fmt+strlen(fmt), fmt_);
>      }

>      //  他のメンバー、前節同様
>     };

//1 | 静的関数 `xindex()` は、補助記憶領域の配列に対するインデックスの予約に関係があります。また、インデックスに対するアクセス関数のはたらきもあります。
//2 | 補助記憶領域の配列の予約スロットは、オブジェクト自身のアドレスで埋まります。

対応して変更されたマニピュレータの内容を、次に示します。

>     template <class charT, class Traits>
>     inline basic_ostream<charT,Traits>&
>     sfmt(basic_ostream<charT,Traits>& ostr, const char* f)
>     {
>      if (ostr.pword(odatstream<charT,Traits>::xindex()) == &ostr) //1
>         ((odatstream<charT,Traits>&)ostr).fmt(f);
>      return ostr;
>     }

//1 | マニピュレータ関数では、ストリームの記憶領域の予約スロットが、ストリームのアドレスかどうかを検査します。ストリームのアドレスであれば、ストリームは日付出力ストリームとみなされます。

この節で説明した方法は、安全ではないので注意してください。日付出力ストリームの補助記憶領域の予約スロットへのアクセスを、日付ストリームとその関連関数、およびクラスだけに限定できないためです。基本的に、種類を問わずあらゆるストリームオブジェクトが `iword()` や `pword()` を通じてエントリにアクセスすることができます。目的の関数だけにアクセス権限を設定できるかどうかは、プログラミングの規定次第です。ただし、記憶領域の内容に関して、すべてのストリームが同じ内容を求めるとは考えられません。ストリームオブジェクトのアドレスを、実行時の型識別子として確認する代わりに、記憶内の一定の整数や一定の文字列に対するポインタなどを使用する方法もあります。RTTI の代用機能を表すのは、予約インデックスおよび想定内容の組み合わせということに注意してください。

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

OEM リリース, 1998 年 6 月