2011-12-25 12 views
2

継承されたクラスのポインタのマップを作成できるかどうか疑問に思っています。ここで私は何をしようとしているの例です:私が得る継承クラスのstd :: mapを作成できますか?

#include <string> 
#include <map> 

using namespace std; 

class BaseClass 
{ 
    string s; 
}; 

class Derived1 : public BaseClass 
{ 
    int i; 
}; 

class Derived2 : public Derived1 
{ 
    float f; 
}; 

// Here's what I was trying, but isn't working 
template<class myClass> 
map<string, myClass>m; 

int main() 
{ 
    // Add BaseClasses, Derived1's, and/or Derived2's to m here 
    return 0; 
} 

エラーは以下のとおりです。

main.cpp(23): error C2133: 'm' : unknown size 
main.cpp(23): error C2998: 'std::map<std::string,myClass>m' : cannot be a template definition

それが可能だ場合、私はこのエラーを取得していますが、私は思ったんだけど、なぜ私が手異なるレベルの継承クラスを保持できるマップを作成しますか?そうでない場合は、さまざまなクラスタイプを保持できる管理システムを作成することは可能ですか?あるいは、私は別のマップ/ベクトル/配列/等を作らなければなりません。クラスの種類ごとに?

+1

「BaseClass *」を保存しているだけではない理由がありましたか? –

+0

'BaseClass *'のマップを持ち、その機能を維持しながら 'Derived1 *'と 'Derived2 *'を追加することはできますか?以前のようなものを試したことは覚えていますが、 'BaseClass *'のマップは、元のものとは無関係に、私がそれを 'BaseClass *'に変換しているように見えます。 – JJandDjango

+0

派生クラスへのポインタは、暗黙的にベースクラスへのポインタに変換できます(そうです)が、ポインタがインスタンスを指している派生型を把握する方法が必要です。次に、ベースをキャストしなければなりません派生関数を使用するための派生ポインタへのポインタ。 –

答えて

1

クラスと関数にはテンプレートがありますが、インスタンスではではなくです。

BaseClass*の地図に固執する必要があります。

3

はい、継承されたクラスをマップに格納できますが、オブジェクト自体ではなく、それらを指すポインタです。ここでは簡単な例は、(それがポインタにメモリ管理が欠如している)最初の

#include <iostream> 
#include <string> 
#include <map> 
#include <utility> 

using namespace std; 

class BaseClass 
{ 
    string s; 
public: 
    BaseClass() { s = "BaseClass";} 
    virtual void print() 
    { 
     cout << s << std::endl; 
    } 
}; 

class Derived1 : public BaseClass 
{ 
    int i; 
public: 
    Derived1() { i = 10; } 
    void print() 
    { 
     cout << i << std::endl; 
    } 

}; 

class Derived2 : public Derived1 
{ 
    float f; 
public: 
    Derived2() { f = 4.3;} 
    void print() 
    { 
     cout << f << std::endl; 
    } 
}; 

int main() 
{ 
    map<string, BaseClass*>m; 
    m.insert(make_pair("base", new BaseClass())); 
    m.insert(make_pair("d1", new Derived1())); 
    m.insert(make_pair("d2", new Derived2())); 
    m["base"]->print(); 
    m["d1"]->print(); 
    m["d2"]->print(); 

    return 0; 
} 
+0

「myClass」がどこでどのように宣言されてマップに使用されるのか聞いてもよろしいですか? – JJandDjango

+0

私はこの例を修正しました。もう一度見てください。 – Anton

2

まずものです:

template<class myClas> 
map<string, myClass> m; 

これは、有効なC++ではないとだけtemplate aliasのようなものを意味するが、私は信じて、それがある可能性がありあなたが探しているものではありません。

C++でポリモーフィックオブジェクトを格納することは、スライス(派生型の値から基本型の値を構築する)によって複雑になります。動的多型は、参照またはポインタを介してのみ処理できます。マップがコールスタックの下を通過する場合は、std::refまたはboost::refを潜在的に使用できますが、これには注意が必要です。しばしば、ベースへのポインタの格納は、移動する方法です:std::map<std::string, base*>。割り当て解除の管理はかなり面倒です。共有セマンティクスが必要かどうかによって、std::map<std::string, std::unique_ptr>またはstd::map<std::string, std::shared_ptr>のいずれかが優先されます。

基本的な例。誰かがこれをもっと意味のあるものに置き換えるべきです。

#include <memory> 
#include <string> 
#include <map> 
#include <iostream> 

class animal 
{ 
public: 
    virtual ~animal() {}; 
    virtual void make_sound() const = 0; 
}; 

class dog : public animal 
{ 
public: 
    void make_sound() const { std::cout << "bark" << std::endl; } 
}; 
class bird : public animal 
{ 
public: 
    void make_sound() const { std::cout << "chirp" << std::endl; } 
}; 

int main() 
{ 
    std::map<std::string, std::unique_ptr<animal>> m; 
    m.insert(std::make_pair("stupid_dog_name", new dog)); 
    m.insert(std::make_pair("stupid_bird_name", new bird)); 
    m["stupid_dog_name"]->make_sound(); 
    return 0; 
} 
+0

あなたの例は良いですが、C++ 11の一部であるstd :: unique_ptrを使用していますが、現時点で広く使われているわけではありません。私は、C++世界で初心者には新しい標準機能を推奨しません。 – Anton

+0

@Anton私は物事を他の方法で見る。すべての主要な実装は今、 'unique_ptr'をサポートしています。なぜこれを行う古い方法を学ぶべきなのかという正当な理由はありません。メンテナンスの他に、彼はそのようなコードを見て、それを現代のイディオムに置き換えます。 – pmr

+0

まあ、完璧な世界では誰もが最新のバージョンの技術を使用するでしょう。しかし、真実は、あなたが会社の規則やその他の手段によって制限されている場合、実生活ではあまりにも多くの場合があるということです。あなたが会社で仕事を始めたとき、彼らはあなたに新鮮なVisualStudioや最新のgccコンパイラを与えることは許されません。このような状況では、知識を既存の環境にダウングレードするのは本当に苦痛です。もちろん、自分自身やいくつかのオープンソースプロジェクトのコードを書くときには当てはまりません。 – Anton

1

以下は、antonによって提案されたソリューションの拡張です。

#include <iostream> 
#include <string> 
#include <map> 
#include <utility> 

using namespace std; 

class BaseClass 
{ 
    string s; 

public: 
    BaseClass() { s = "BaseClass";} 
virtual ~ BaseClass(){} 
virtual void print()=0; 
}; 


class Derived1 : public BaseClass 
{ 
    int i; 
public: 
    Derived1() { i = 10; } 
    void print() 
    { 
     cout << i << std::endl; 
    } 

}; 

class Derived2 : public Derived1 
{ 
    float f; 
public: 
    Derived2() { f = 4.3;} 
    void print() 
    { 
     cout << f << std::endl; 
    } 
}; 

class factory 
{ 
map<string, BaseClass*>m; 
BaseClass* obj; 
public: 
factory() 
{ 
obj=NULL; 
} 
BaseClass* FindType(string s); 
void AddType(string s,BaseClass *obj); 
void deleter(); 
~factory(){cout<<"deleting objects from map"<<endl; 
deleter(); 
} 
}; 
void factory :: AddType(string s,BaseClass* obj) 
{ 
m.insert(make_pair(s,obj)); 
} 
void factory ::deleter() 
{ 

    for (auto pObj = m.begin(); 
     pObj != m.end(); ++pObj) { 

     delete pObj->second; 
    } 

    m.clear(); 

} 
BaseClass* factory::FindType(string s) 
{ 
if(m.find(s)!=m.end()) 
{ 

return m[s]; 
} 

return NULL; 
} 

int main() 
{ 
    BaseClass* obj; 
    factory fact_obj; 
    fact_obj.AddType("d1",new Derived1()); 
    fact_obj.AddType("d2",new Derived2()); 
    obj=fact_obj.FindType("d1"); 
    if(obj!=NULL) 
     { 
    obj->print(); 
     } 
    obj=fact_obj.FindType("d2"); 
    if(obj!=NULL) 
    { 
    obj->print(); 
    } 

    return 0; 
} 
関連する問題