2012-10-10 103 views
2

我想有一個容器(讓我們說一個std ::向量),將容納各種繼承類型,並將實例化它們,.i.e。類的向量 - >對象的向量。C++容器的繼承類的類型

例如:預先

class A{}; 

class B: public class A 
{}; 

class C: public class A 
{}; 

void main() 
{ 
    std::vector<of inherited A types> typesVec; 
    std::vector<A*> objectsVec; 

    typesVec.push_back(class B); 
    typesVec.push_back(class C); 

    for (int i = 0; i < typesVec.size(); i++) 
    { 
     A* pA = new typesVec.at(i); 
     objectsVec.push_back(pA); 
    } 

} 

謝謝..

+0

你需要'typesVec'來動態填充嗎?也就是說,你想在運行時包含或排除某些類型嗎? –

+0

你接受答案的速度非常快...... –

回答

6

這不是在C++可能(至少不直接地)。我可以看到這發生在有反射的語言中,但C++沒有。

您可以改爲創建工廠或創建指定類型對象的方法。

而是有一個類型的載體,你有對象生成的向量(足夠接近,對不對?):

class A{}; 

class B: public class A 
{}; 

class C: public class A 
{}; 

struct AFactory 
{ 
    virtual A* create() { return new A; } 
}; 
struct BFactory : AFactory 
{ 

    virtual A* create() { return new B; } 
}; 
struct CFactory : AFactory 
{ 

    virtual A* create() { return new C; } 
}; 

//... 

typesVec.push_back(new BFactory); 
typesVec.push_back(new CFactory); 

for (int i = 0; i < typesVec.size(); i++) 
{ 
    A* pA = typesVec.at(i)->create(); 
    objectsVec.push_back(pA); 
} 
+0

「對象生成器」也被稱爲*工廠*。 –

+0

@AlexandreC。 「你可以做的是創建一個**工廠**或簡單地創建指定類型對象的方法。」 –

+0

Lucian,非常感謝!我被困了一段時間......我的確最終使用了一種工廠,雖然略有不同。 – zuuz

0

只是一個快速的解決方案草圖:

C++標準不不提供直接調用構造函數。因此你不能有構造函數的指針;你可以,但是,有一個包裝函數「創造」,是這樣的:

template<typename T> 
T* create() { 
    return (new T(); 
} 

提供重載創建定義爲一個參數,兩個參數,...或嘗試使用可變參數模板;或者,如果您已經知道需要什麼類型,則可以專門創建創建函數。然後你可以有一個指向創建函數的函數指針:

&create<TheType> 

請注意,這個函數的簽名取決於使用的類型。但是,您可以創建一個結構,其中包含模板類型的typdefs,類型指針的typedef以及作爲仿函數的創建函數operator()

因此,您可以擁有兩個向量,一個用於指向create函數的函數指針,或者替代上述結構,另一個指向實際對象。在你只有繼承類型的情況下,你可能能夠爲每個繼承類型B,C,...定義函數A* createB() { return new B(); },A* createC() { return new C(); },...並且具有用於指向這些創建函數的指針的向量以及用於A指針。

0

我可能會指出Andrei Alesandrescu的書「Modern C++ Design」(或他在書中描述的Loki庫)和關於類型列表的章節。這會要求您在編譯時執行typeVec.insert(type)

0

有模板的可重用方法。這是一個普通的工廠派生類型帶有一個installcreate方法,它可以讓你寫這樣的代碼:

int main() { 
    TypeVector<Base> t; 
    t.install<Foo>("Foo"); 
    t.install<Bar>("Bar"); 

    t.create("Foo")->hello(); 
} 

注意這是一個草圖的實現。在現實世界中,您可以提供另一個模板參數來指定潛在的容器類型(對於少數類型,vector可能比set更有效)。

類型矢量是這樣的:

模板 類創建者;

template <typename Base> 
class TypeVector { 
public: 
    template <typename Derived> 
    void install (std::string const &name) ; 

    std::shared_ptr<Base> create (std::string const &name) const; 

private: 
    struct Meta { 
     Meta(std::shared_ptr<Creator<Base>> creator, std::string const &name) 
      : creator(creator), name(name) {} 

     std::shared_ptr<Creator<Base>> creator; 
     std::string name; 
    }; 

    std::vector<Meta> creators_; 
}; 

我們莫名其妙地需要一種方法來類型中的分配方式。我們不喜歡它boost::shared_ptr,它結合了一個抽象基類和模板派生類:

template <typename Base> 
class Creator { 
public: 
    virtual ~Creator() {}   
    virtual std::shared_ptr<Base> create() const = 0; 
}; 

template <typename Base, typename Derived> 
class ConcreteCreator : public Creator<Base> { 
public: 
    virtual std::shared_ptr<Base> create() const { 
     return std::shared_ptr<Base>{new Derived()}; 
    } 
}; 

的「具體的創造者」是能夠分配一個實際的對象,並返回一個指針到基地了。

最後,這裏是TypeVector::installTypeVector::create的實現:

template <typename Base> 
template <typename Derived> 
void 
TypeVector<Base>::install (std::string const &name) 
{ 
    creators_.emplace_back(
     std::shared_ptr<Creator<Base>>(new ConcreteCreator<Base, Derived>()), 
     name); 
} 

template <typename Base> 
std::shared_ptr<Base> 
TypeVector<Base>::create (std::string const &name) const 
{ 
    for (auto m : creators_) { 
     if (name == m.name) return m.creator->create(); 
    } 
    throw std::runtime_error("..."); 
} 

最後,這是一個測試:

#include <iostream> 
struct Base { 
    virtual ~Base() {} 
    virtual void hello() const = 0; 
}; 
struct Foo : Base { 
    virtual void hello() const { std::cout << "I am a Foo\n"; } 
}; 
struct Bar : Base { 
    virtual void hello() const { std::cout << "I am a Bar\n"; } 
}; 

int main() { 
    TypeVector<Base> t; 
    t.install<Foo>("Foo"); 
    t.install<Bar>("Bar"); 

    t.create("Foo")->hello(); 
} 

你可以更進一步,做任何構造函數調用像代碼.. 。

... 
    Bar(Color, Age, int) 
... 
t.create("Foo", Color::Red, Age::TooOld, 42) 

......但這需要一個aw esome掌握可變參數模板參數列表,以及如何將它們摺疊成構造函數調用(可以完成並已完成,但會爆炸此答案)。