1

テンプレート化された基本クラスから派生したオブジェクトを STL マップに格納しようとしています。ただし、派生 (または実際にはベース) オブジェクトを挿入しようとすると、以下が返されます。

C2440 'initializing' : cannot convert from 'CBase<T> ' to 'CBase<T>'

派生クラスの使用は、STL コンテナーを異種混合にする方法の 1 つとして認められていることを理解しています (http://www.parashift.com/c++-faq-lite/containers.html#faq-34.4)。このコンテキストでテンプレートを使用できるかどうかを知りたいです。テンプレート化されていない派生クラスで重複した宣言を行う代わりに、コンパイル時にさまざまな型に対してインスタンス化される、基本クラスでコンテナーの範囲の宣言を 1 つ持つことができるので、非常に便利です。

私のコードは次のとおりです。

//Header
using namespace std;

template<class T>
class CBase
{
    public:
        CBase::CBase() {};
        virtual CBase::~CBase() {};
        vector<pair<int, T> > RetrieveVect() { return vect; };

    private:
        vector<pair<int, T> > vect;
};

class CDerivedString : public CBase<string>
{
    ...
};

class CDerivedInt : public CBase<int>
{
    ...
};

//cpp
int main(void)
{
    //Map specialised for pointer to base class
    map<string, CBase<class T>* > m_myMap;

    string s = "key";

    //Create and insert object (base class)
    CBase<int> *dataInt = new CBase();
    //The following results in error C2440: 'initializing' : cannot convert from 'CBase<T> ' to 'CBase<T>
    m_myMap.insert(std::make_pair(s, dataInt));

    //Create and insert object (derived class)
    CBase<int> *dataBase = new CBase<int>();
    //The following results in error C2440: 'initializing' : cannot convert from 'CBase<T> ' to 'CBase<T>
    m_myMap.insert(pair<string, CBase<class T>* >(s, static_cast<CBase*>(dataInt)));
}

派生クラス ポインターで dynamic_cast を実行して、基本ポインター型にキャストしようとしましたが、これも機能しませんでした。

//error C2440: 'static_cast' : cannot convert from 'CBase<T> *' to 'CBase<T> *'
m_myMap.insert(pair<string, CBase<class T>* >(s, static_cast<CBase<class T>*>(dataInt)));  
4

3 に答える 3

6

次の行:

map<string, CBase<class T>* > m_myMap;

ほぼ確実に、あなたが思っていることを意味するわけではありません。これは次と同等です。

map<string, CBase<T>* > m_myMap;

つまり、'T' はテンプレート パラメータではなく具象クラスです。もちろん、クラス間に関係はありません。

CBase<int> 

CBase<T>

したがって、エラー メッセージ - 具象クラス 'T' を定義した (または意図した) ことはありません。正しいベースを使用してSCFrenchのコメントを受け取り、それをマップで使用します<>:

map<string, CBase<int>* > m_myIntMap;

具体的な CDerivedInt* オブジェクトを格納できます。オブジェクトを格納する場合は、完全に汎用的なベースを定義します。

 class CBaseAbc 
     { 
        virtual ~CBaseAbc() = 0;
     };
 template<class T>
 class CBase : public CBaseAbc 
    {
     // etc.
    };

map<string, CBaseAbc* > m_myAnthingMap;
于 2011-02-07T02:26:38.610 に答える
1

Boost の Pointer Containersを使用します。これは、試した「基本クラスへのポインターに特化したマップ」を正確に提供します。

// Use whichever is appropriate since you've written CBase as a template:
boost::ptr_map<string, CBase<int> > m_myMap;
boost::ptr_map<string, CBase<string> > m_myMap;

// If CBase were instead not a template base class:
boost::ptr_map<string, CBase> m_myMap;

CBase のインターフェイスで T を使用しているため、CBase をテンプレートとして保持したいようですが、その場合、CBase<int> と CBase<string> から派生したクラスの間に共通の基底クラスがないことに注意してください。 2 つの異なる型であり、いずれかから派生したクラスを 1 つのコンテナーに格納することはできません。

于 2011-02-07T01:33:25.677 に答える
0

に格納する基本クラスが必要std::mapです。テンプレート化されていないクラスまたはテンプレートの特定のインスタンスである必要があります。CBaseすべてのインスタンスに共通の基本クラスがない限り、「 の任意のインスタンスを格納することはできません。オブジェクトの有効期間を使用するboost::shared_ptrか、自動的に管理することを検討することもできます。std::shared_ptr

于 2011-02-07T01:33:49.380 に答える