ポリシークラスとホストクラスは、言語に支援された実装形態ではない。標準でない実装手段を用いる場合は、言語によるプログラミングサポートが乏しくなり、設計の意図をコードで表明できない箇所が発生する。コード化できないルールは言語処理系で検証できないので、文書として明示し、人手あるいは補助ツールで注意深く守るようにしなければならない。
ここでは、ホストクラスがポリシークラスに対して要求するルール、あるいはその逆のルールのうち、コード化可能なものを列挙する。
ホストクラス側でコード化可能なポリシークラスに対するルールは次の通り。
許可する場合、public継承を用いる。禁止する場合、publicでない継承あるいは他の手段を用いる。
目的の名前を型名として使用する。例えば次のようにする:
typedef typename policy::target something;
目的の名前を定数として使用する。例えば次のようにする:
enum { something = policy::target };
非静的メンバ関数から目的の関数を呼び出す。例えば次のようにする:
void func() { policy::target(); }
policy::targetが非静的か静的か、多重定義されているか否かは問えない。
例外仕様は問えない。だが、例えば次のようにすると:
void func() throw() { policy::target(); }
policy::targetの例外仕様がthrow()ではないとき、処理系と状況によってはコンパイラによる警告を期待できる。
目的のcv修飾子を持つ非静的メンバ関数から目的の関数を呼び出す。例えば次のようにする:
void func() const { policy::target(); }
policy::targetが非静的か静的か、多重定義されているか否かは問えない。
静的メンバ関数から目的の関数を呼び出す。例えば次のようにする:
static void func() { policy::target(); }
policy::targetが多重定義されているか否かは問えない。
要求する形態のコンストラクタなどを呼び出す。
要求する形態のpolicy::operator=を呼び出す。
メンバ関数と同様に行う。
using宣言を用いる。例えばusing policy::target;などとする。ポリシークラスでその名前が関数として多重定義されていれば、多重性もそのまま引き継がれる。言語規約上、アクセス権限の降格(例えばpublicからprivateへの変更)はできない。アクセス権限の据え置きと昇格はできる。
同名の定義を行う。例えば次のようにする:
void func() { policy::func(); }
これにより、policy::funcの関数シグネチャ、アクセス権限、多重性はホストクラス外部からは参照不能になる。
同名かつ無効な定義を行う。例えば次のようにする:
private: typedef void target;
これにより、ポリシークラスが名前targetをホストクラスの公開インタフェースへと追加することができなくなる。ただし、ホストクラス内からpolicy::targetを参照することは禁止できない。
ポリシークラス側でコード化可能なホストクラスに対するルールは次の通り。
ポリシークラス側でコード化可能なホストクラスに対するルール
デストラクタをprotectedにする。
追加する公開インタフェースをpublicメンバとして定義する。
ホストクラスに対するルールではないが、ポリシークラスは抽象クラスではないため、デストラクタは非仮想にする必要がある。
通常のクラスと同様、非公開でよいものはprivateにする。ホストクラスから要求された機能はprotectedにする。ただし、ホストクラスから要求された型名で、ホストクラス外で使用する必要があるもの(例えばホストクラスがポリシークラスを継承する際にテンプレートパラメータに使用する型名)については、publicにする。
また、例外安全性のために、例外を投げないメンバ関数swapを定義しておくと便利である。空クラスでなければ非静的メンバ関数、空クラスであれば静的メンバ関数として定義するとよい。
以下に例を示す。
例 5.4. メンバ関数swapの定義
class some_policy
{
public:
void swap(some_policy& rhs) throw() { /* ... */ }
};
class empty_policy
{
public:
static void swap(empty_policy&) throw() {}
};
template <class P>
class host
: public P
{
public:
void swap(host& rhs) throw()
{ P::swap(rhs); }
host& operator=(host rhs)
{ swap(rhs); return *this; }
};
ホストクラスhostは、ポリシークラスのswapが静的か非静的かを区別する必要はない。