データ処理クラスライブラリの開発>クラス階層

 ここではテキストやビットマップ、音声など各種のデータを統一的なインターフェースで操作できるクラスライブラリを開発してみます。イメージとしては、それぞれのデータがオブジェクトとしてコンテナに格納され、検索や保存、ネット上への送信などの各種操作をインターフェースを通して行えるような感じでしょうか。ビットマップや文章を編集する日常的なアプリケーションはもちろん、データベースの開発にも利用しやすいクラスライブラリにまとめられれば、と思っています。

 今回は、全体のクラス階層の大枠を考えながら、最も基本的なデータであるバッファを扱うクラスを実装してみることにします。

クラス階層

 クラス階層は、まずデータを扱うためのいくつかのインターフェースを定義し、実際のデータを扱うクラスはそれらのインターフェースの中から必要なものを実装する形にします。ただし、すべてのオブジェクトはオブジェクトの基本インターフェースであるD2IObjectクラスを継承するものとし、このインターフェースを通してオブジェクトに関する情報、さらにオブジェクトが持つインターフェースを取得できるようにしましょう。

D2IObjectクラス

  class D2IObject {

  public:

      virtual UI32 getObjectType() const=0;
      virtual UI8 getVersion() const=0;
      virtual UI8 getDataType() const=0;
      virtual UI16 getEncoding() const=0;
      virtual void * getInterface(UI32) const=0;
      virtual CSTR getCSTR()=0;

      virtual ~D2IObject() {}

  };

 今回は、型名を以下のようにtypedefしています。

  typedef BYTE UI8;
  typedef WORD UI16;
  typedef DWORD UI32;
  typedef char I8;
  typedef short I16;
  typedef int I32;

  typedef LPBYTE BUF;
  typedef char CHR;
  typedef char * CSTR;

 これらの関数のうち

  virtual UI32 getObjectType() const=0;
  virtual UI8 getVersion() const=0;
  virtual UI8 getDataType() const=0;
  virtual UI16 getEncoding() const=0;

 は、オブジェクト自体やオブジェクトが保持するデータの形式に関する情報を取得するものです。また、getInterface()は、インターフェースを指定するとオブジェクトがそのインターフェースに対応している場合はそのインターフェースのポインタを返します。getCSTR()は、オブジェクトの文字列表現を返します。

 すべてのオブジェクトはこのD2IObjectのサブクラスなので、これらの関数はすべてのオブジェクトで使用できます。各種のデータを格納したオブジェクトを統一的に扱う場合は、D2IObject型ポインタにオブジェクトを格納しgetDataType()などでデータの種類を判別しながら、必要に応じてgetInterface()で行いたい操作のためのインターフェースを取得する形になるでしょう。

 今回は、バッファを扱うためのデータクラスを作ってみるので、以下のようなバッファを読み書きするインターフェースを定義してみました。関数の機能は、大体名前どおりです。

  class D2IBufferReader {

  public:

      virtual BUF copyBuffer() const=0;
      virtual I32 getBufferSize() const=0;
      virtual UI8 readBufferByte(I32) const=0;
      virtual bool equalBuffer(const BUF,I32) const=0;
      virtual bool equalBuffer(const D2IBufferReader *) const=0;

      ~D2IBufferReader() {}

  };

  class D2IBufferWriter {

  public:

      virtual BUF getBuffer() const=0;
      virtual bool resizeBuffer(I32,bool bArg=true)=0;
      virtual bool assignBuffer(const BUF,I32)=0;
      virtual bool assignBuffer(const D2IBufferReader *)=0;
      virtual bool writeBuffer(const BUF,I32,I32)=0;
      virtual bool writeBufferByte(UI8,I32)=0;
      virtual bool fillBuffer(UI8,I32,I32)=0;
      virtual bool appendBuffer(const BUF,I32)=0;
      virtual bool appendBuffer(const D2IBufferReader *)=0;
      virtual bool appendBufferByte(UI8)=0;

      ~D2IBufferWriter() {}

  };

 次に、「バッファに格納されたデータを持つオブジェクト」を扱うためのインターフェースD2IBufferedObjectを、D2IObject/D2IBufferReader/D2IBufferWriterの各インターフェース(抽象クラス)を多重継承する形で定義しておきます。

  class D2IBufferedObject:public D2IObject,public D2IBufferReader,public D2IBufferWriter {

  public:

      virtual ~D2IBufferedObject() {}

  };

バッファオブジェクトクラスの実装

 以上で、バッファ形式のデータオブジェクトを操作(オブジェクト全般の操作とバッファの読み書き)するD2IBufferedObjectインターフェースができました。今回のバッファオブジェクトクラスD2CBufferは、このD2IBufferedObjectインターフェースを以下のような形で実装することにしましょう。

  class D2CBuffer:public D2IBufferedObject {

  public:

      D2CBuffer();
      D2CBuffer(const BUF,I32);
      D2CBuffer(const D2IBufferReader *);

      virtual bool clear();

      virtual ~D2CBuffer();

      // D2IObject

      virtual UI32 getObjectType() const;
      virtual UI8 getVersion() const;
      virtual UI8 getDataType() const;
      virtual UI16 getEncoding() const;
      virtual void * getInterface(UI32) const;
      virtual CSTR getCSTR();

      // D2IBufferReader

      virtual BUF copyBuffer() const;
      virtual I32 getBufferSize() const;
      virtual UI8 readBufferByte(I32) const;
      virtual bool equalBuffer(const BUF,I32) const;
      virtual bool equalBuffer(const D2IBufferReader *) const;

      // D2IBufferWriter

      virtual BUF getBuffer() const;
      virtual bool resizeBuffer(I32,bool bArg=true);
      virtual bool assignBuffer(const BUF,I32);
      virtual bool assignBuffer(const D2IBufferReader *);
      virtual bool writeBuffer(const BUF,I32,I32);
      virtual bool writeBufferByte(UI8,I32);
      virtual bool fillBuffer(UI8,I32,I32);
      virtual bool appendBuffer(const BUF,I32);
      virtual bool appendBuffer(const D2IBufferReader *);
      virtual bool appendBufferByte(UI8);

  protected:

      BUF m_bfBuffer;
      CSTR m_csStr;
      I32 m_i32BufferSize;

      virtual bool setBuffer(const BUF);
      virtual bool setBufferSize(I32);
      virtual bool deleteBuffer();

  };

 バッファの操作は、protectedポインタm_bfBufferにバッファを確保して行います。m_csStrgetCSTR()で返すための文字列表現ですが、今回は単純にバッファをコピーして無条件に末尾に0を付加して返すだけにしました。まあ、今回は実装というよりは設計のテストですから、実際のバッファ周りの実装はあまり気にしないでください(^^;。

 指定されたインターフェースを返すgetInterface()は、以下のように指定されたインターフェースを持っていれば自分自身のポインタをそのインターフェースにキャストして返します。

  void * D2CBuffer::getInterface(UI32 u32Arg) const {

      switch (u32Arg) {

      case ID_D2IObject:

          return (D2IObject *)this;

      case ID_D2IBufferReader:

          return (D2IBufferReader *)this;

      case ID_D2IBufferWriter:

          return (D2IBufferWriter *)this;

      case ID_D2IBufferedObject:

          return (D2IBufferedObject *)this;

      default:

          return NULL;

      }

  };

プログラム

 今回のプログラムは、D2CBufferとインターフェースのテストプログラムです。最初にD2CBufferのインスタンスbTestbTest2を作り、適当な文字列を入れておきます。続いて

  D2IObject *poTest=new D2CBuffer(&bTest);

 としてpoTestを生成し、D2IObject型ポインタに格納しておきます。次に、D2IObjectインターフェースを通してD2IBufferWriterインターフェースを取得し、そのD2IBufferWriterインターフェースでbTestのバッファに追記してみました。

  D2IBufferWriter *pbwTest=(D2IBufferWriter *)poTest->getInterface(ID_D2IBufferWriter);

  pbwTest->appendBufferByte('A');

 結果を見ると、D2IObjectを通したインターフェースの取得・インターフェースによる操作という基本的な部分はうまく動くようですね。次回からは、さまざまなデータ形式のクラスやデータ操作用の各種インターフェースを作っていくことにしましょう。

プログラムダウンロード(ODLIB1.ZIP/5KB)
戻る トップへ