重要な情報が 1 つ欠けていると思います。それは、特殊化されていないメソッドがTBase
クラスの仮想メソッドをオーバーライドしていないかということです。これがここでの中心的な問題です。
そうでない場合は、特殊化されていないメソッド用に別のクラスを作成し、クラス内の両方のクラスから (パブリックに) 継承することができますCTemplateInherit
。問題が解決しました。
ただし、特殊化されていないメソッドが TBase クラスの仮想メソッドをオーバーライドする場合は、少しだけ複雑になります。
解決策 1) 特殊化されていないすべての機能を取得し、それらを 1 つの「詳細」ヘッダーに再グループ化します。(非テンプレート) フリー関数のグループとして (入出力をパラメーターとして渡すだけで十分簡単な場合)、または必要な特殊化されていないデータ メンバーを含む (非テンプレート) クラスとして。次に、これらすべての関数を対応する cpp ファイル (後で DLL にコンパイルします) 内で定義 (実装) します。
次に、CTemplateInherit
クラス テンプレートで、特殊化されていない関数呼び出しを一連の「詳細」関数に転送するだけです。テンプレートはデフォルトでインライン化されるため、オーバーヘッドはゼロになります。「詳細」関数を 1 つのクラス (非テンプレート) に再グループ化する必要がある場合は、単純にprivate
継承を使用して、関数名の競合を防ぎます。次に、他の継承されたデータ メンバーと同様に「詳細」クラスのデータ メンバーにアクセスできます。また、特殊化されていない関数呼び出しを、DLL にコンパイルできる「詳細」クラスの実装に転送できます ( DLLからクラスをエクスポートするための適切なフレームワーク(プレーンC ++には信頼できるメカニズムがないため)ですが、あなたの質問はあなたがそうしていることを暗示しているようです)。
このソリューションの唯一の問題は、いくつかの単純な転送関数を作成する煩わしさです。しかし、私見ですが、これは実装を DLL に隠すために支払う妥当な代償です (ほとんどの場合、それを実行したい場合は、最終的に多数のラッパー関数を作成することになります)。
解決策 2) 基本クラスからの特殊化されていない仮想関数のセットがある場合、そのサブセットは実際の型に依存していませんTBase
(つまり、それらの関数のプロトタイプはそれなしで形成できます)。次に、その関数のサブセットを、TBase
継承元であると予想される別の基本クラスに再グループ化できることを意味します。と呼びましょうTNonSpecialBase
。この時点で、次の階層を設定できます。
class TNonSpecialBase {
// set of pure-virtual functions that are not special.
};
// this is an example of a class that could act as a TBase:
class TExampleBase : public virtual TNonSpecialBase {
// set of virtual functions that are special to TExampleBase.
};
class CNonSpecialDerived : public virtual TNonSpecialBase {
// declaration of non-specialized functions that override the function in TNonSpecialBase.
};
template <typename TBase>
class CTemplateInherit : public TBase, public CNonSpecialDerived {
// set of virtual functions that are specialized for the template argument TBase.
};
上記のセットアップでは、特殊化された関数は のヘッダー ファイルで終わる必要がありますがCTemplateInherit
、再グループ化された特殊化されていない関数CNonSpecialDerived
は別の cpp ファイルで定義できます (そして DLL にコンパイルされます)。ここでの魔法のトリックは、仮想継承を使用して、最終クラスが基本クラス用の単一の仮想テーブルを持つことを可能にすることですTNonSpecialBase
。言い換えれば、これにより、TBase がそれらの関数をオーバーライドしない限り、クラスCNonSpecialDerived
は から継承された TBase の仮想関数をオーバーライドできます (この場合、コンパイラはそれをあいまいと呼びます)。TNonSpecialBase
このようにして、ユーザーはTBase
オブジェクトへのポインターを処理し、その仮想関数のいずれかを呼び出すことができます。これにより、CTemplateInherit
実装 (特殊化) へのディスパッチまたはCNonSpecialDerived
実装 (おそらく DLL 内)。