2

テンプレートクラスについて質問があります。たとえば、このクラスを受講してください

template<class TBase> class CTemplateInherit : public TBase
{
public:

    virtual void DoNonSpecializedWork();
    virtual void DoTemplateWork();
    virtual ~CTemplateInherit();
};

// In header file
template<class TBase>
bool CTemplateInherit<TBase>::DoTemplateWork()
{
    std::wcout << L"CTemplateInherit::DoTemplateWork" << std::endl;
    TBase::DoWork();
    return true;
}

// In CPP file
bool CTemplateInherit::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

ここで、dllexport を使用して CPP ファイルで特殊化されていないメソッドを定義し、特殊化をヘッダーに保持できるようにしたいと考えています。通常、メンバー メソッドをテンプレートとして定義するだけでよいと思いますが、TBase から継承しているため、それは不可能です。

では、どうすればこれを分割できますか?TBase からおそらく 4 つのメソッドのみをオーバーライドし、他の 40 ほどのメソッドを DLL の DLLEXPORT として保持できるようにしたいと考えていますが、特殊化はヘッダー ファイルにあります。

ご提案いただきありがとうございます。

4

3 に答える 3

3

hierarchyクラスを変更したくない場合。

1)ファイル内specializeの必要なすべてのタイプの関数。.cpp

template<>
bool CTemplateInherit<First>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

template<>
bool CTemplateInherit<Second>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

template<>
bool CTemplateInherit<Nth>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

2) 使用

template<typename T>
bool CTemplateInherit<T>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

.cppファイル内ですが、このようなものを使用しますheader

template class CTemplateInherit<First>;
template class CTemplateInherit<Second>;
template class CTemplateInherit<Nth>;

3)ディートマーが示唆するように。

于 2012-09-02T13:14:20.440 に答える
3

何を達成しようとしているのかよくわかりませんが、テンプレートを使用するときは、これらが必要に応じてインスタンス化されていることを確認する必要があります。テンプレート定義をヘッダーに配置すると、コンパイラから暗黙的なインスタンス化を取得できます。関数テンプレートが使用され、このテンプレートの定義が表示されていることがわかると、テンプレートがインスタンス化されます。テンプレートを別の場所に置くと、コンパイラは必要なときにテンプレート定義を認識しないため、暗黙的にインスタンス化されません。ただし、対応する関数テンプレートを自分でインスタンス化できます。たとえば、次のようになります。

// In CPP file
template <class TBase>
bool CTemplateInherit<TBase>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

template bool CTemplateInherit<SomeBase>::DoNotSpecializeWork();
template bool CTemplateInherit<SomeOtherBase>::DoNotSpecializeWork();
于 2012-09-02T13:21:23.940 に答える
1

重要な情報が 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 内)。

于 2012-09-02T15:14:30.597 に答える