負の継承への対応(2)
負の継承への対応を具体的にまとめていく
まず、共通性を侵すことなく可変性を扱う場合は、とくに問題なくあつかえるという前提です。
また、負の可変性は正の可変性と対応した技術で実現します。例えば、正の可変性をテンプレートで
実現した場合は、負の可変性はテンプレートの特殊化になります。
負の可変性を扱うメカニズム
・テンプレートの特殊化
共通の形:型によらず共通
template < class T> class Stack{ StackRep<T> *rep; } template < class T> class StackRep{ StackRep<T> *next; T* rep }
上記では、ポインタを持った構造体で管理しているが、整数型に対しては性能要件から動的配列はとれず、
要素数も決まっている場合があった場合は、テンプレートの特殊化で以下のようにできる。
template < > class Stack<int>{ static int rep[10000]; }
・デフォルト引数
アルゴリズムに強い共通性がある場合で、値に対して弱いバリエーションがあった場合、
(言い換えると、十中八九はこの値だけど、ごくまれにコレというようなケース)
・データのキャンセル
//テキストバッファを扱うクラス template <class CharSet > class TextBuffer{ public: Line<CharSet> getLine(const LineNumber&); private: LineNumber firstLine, lastLine; int currentLine; //はじめと最後の行、現在の行を扱えるとメンバ変数がいる }
1行だけ扱うテキストバッファが必要で、テキストバッファに対する機能を有している上記を継承する場合は、
複数行扱うメンバーは邪魔になる。
//ページ単位でテキストバッファを扱う template <class CharSet > class PageBuffer : TextBuffer<CharSet>{ public: } //1行単位でテキストバッファを扱う template <class CharSet > class LineBuffer : TextBuffer<CharSet>{ public: }
派生クラスで、基底クラスのメンバをキャンセルすることはできないため、可変性を外側にくくりだす。
ここでは、ページ単位でテキストバッファを扱うクラスと1行単位で扱うテキストバッファを以下のように定義する。
//まず、それぞれの実装を定義 template <class CharSet > class PageBufferRep : public TextBufferRep<CharSet>{ LineNumber firstLine, lastLine; int currentLine; } template <class CharSet > class LineBufferRep : public TextBufferRep<CharSet> { public: }
上記の実装に対して、クライアントへ提供するハンドルを以下のように定義する。
template <class CharSet > class TextBuffer{ public: Line<CharSet> getLine(const LineNumber&); protected: TexstBufferRep<CharSet>* rep;//最初の例と比較すると、所持していたデータメンバが抽象化されている。 TextBuffer(TexstBufferRep<CharSet>*); //コンストラクタでRepを割り当てる }
最終的にはこうする。
template <class CharSet > class PageBufferBuffer : public TextBuffer<CharSet>{ public: PageBufferBuffer () : TextBuffer<CharSet>(new PagedTextBufferRep){} } template <class CharSet > class LineBufferBuffer : public TextBuffer<CharSet>{ public: LineBufferBuffer () : TextBuffer<CharSet>(new LineBufferRep ){} }
図でいうと、
以下になってます
※
つかれたので、あとで整理しよう