2015-05-29 38 views
0

比如我有基類A和子類B1,B2,B3等如何從隨機子類創建對象?

我想寫點東西像(或另一種方式來做到這一點,它並不重要):

A *randomobject1; 
randomobject1 = A::Getrandomobject(); 

而randomobject1是指向隨機子類的對象的指針。

我不知道該怎麼做!也許我需要存儲對子方法的引用並在之後調用它,或者...我不明白。

我不需要真正的隨機,我需要知道生成對象之前的一些信息。

例如,子類包含一些整數的靜態字段。我需要從包含這個整數的隨機子類生成對象,它大於30(或與其他類型的字段)。 所以,一些整數< 30的類將不參與代。

+0

這沒關係。我只是想解決這個問題。我需要從子類中獲得隨機對象。如何做到這一點並不重要。 –

+0

你有收集兒童班嗎?也許是指向基類的向量?然後只需隨機選擇一個元素。但是,如果您沒有自己的對象集合,那麼不可能找到所有分配和實例化的對象。 –

+0

你到底在幹什麼?如何生成隨機數字?如何創建新對象? – nwp

回答

1

我假設您的getRandomObject函數中已知所有可能的子類,並且您希望在每次調用時創建一個新實例。那麼這是一個可行的解決方案:

A *getRandomObject() { 
    int r = getRandomIntInRange(0, 3); // Some method returning a random int from [0,1,2] 
    switch (r) { 
    case 0: return new B1(); 
    case 1: return new B2(); 
    case 2: return new B3(); 
    default: return NULL; // should never come here... 
} 

UPDATE:
如果你的方法可能不知道的所有可能的子類,登記機構是可能的,在那裏你存儲返回新的實例(工廠)functionoids。

快速概要:

// Somewhere in your code 
A *b1Factory() { return new B1(); } 
A *b2Factory() { return new B2(); } 
A *b3Factory() { return new B3(); } 

// somewhere you have a factory list 
typedef A* (*aSubclassFactoryFunc) (void); 
std::vector<aSubclassFactoryFunc> factories; 

A *getRandomObject() { 
    int r = getRandomIntInRange(0, factories.size()); // Some method returning a random int from [0,1,2,...,factories.size()] 
    return factories[r](); // Call random factory 
} 

新的子類只是必須添加一個工廠方法工廠名單。

更新2
註冊機制,可以做這樣的:

#define REGISTER_A(B) \ 
    struct b_subclass_register_##B {\ 
     b_subclass_register_##B() {\ 
      registerASubclass(b_subclass_register_##B::create);\ 
     }\ 
     static A *create() { return new B; }\ 
    } dummy_instance_##B; 

這是創建一個結構,並創建全球範圍內的虛擬實例的萬客隆。在它的構造函數中,子類是註冊的。

你在你的子類CPP文件使用,如:

REGISTER_A(B1); 
+0

這是一個很好的解決方案,但會有許多子類,如果它可以動態地添加新的子類,這種方法會好得多。 –

0

這是假設你知道你的所有子類提前。如果沒有,您可以創建一個虛擬Clone函數的原型註冊系統。要創建對象,我只需要使用一個隨機數生成器和switch結果來確定要構建哪個類。爲了處理回收內存,我返回一個std::unique_ptr,所以客戶端代碼不需要擔心刪除指針。

struct A { 
    //the random child class factory method 
    static std::unique_ptr<A> Getrandomobject(); 

    //need a virtual destructor so that the child object is deleted properly 
    virtual ~A() =default; 

private: 
    //random number generator 
    static std::mt19937 rng_; 
    //some state to check if the rng has been seeded 
    static bool inited_; 
}; 
std::mt19937 A::rng_; 
bool A::inited_ = false; 

//our child classes 
struct B1:A{}; 
struct B2:A{}; 
struct B3:A{}; 
struct B4:A{}; 

std::unique_ptr<A> A::Getrandomobject() 
{ 
    //seed rng if this is the first call 
    if (!inited_) 
    { 
     rng_.seed(std::random_device()()); 
     inited_ = true; 
    } 

    std::uniform_int_distribution<std::mt19937::result_type> dist(0,3); 
    switch (dist(rng_)) 
    { 
     case 0: return std::make_unique<B1>(); 
     case 1: return std::make_unique<B2>(); 
     case 2: return std::make_unique<B3>(); 
     case 3: return std::make_unique<B4>(); 
     default: return std::make_unique<B1>(); 
    } 
} 

要檢查,這確實給了我們一個隨機的子類,我們可以使用下面的測試代碼(結果將依賴於編譯器由於typeid):

int main() { 
    auto randomobject1 = A::Getrandomobject(); 
    cout << typeid(*(randomobject1.get())).name(); 
    return 0; 
} 
+0

[Demo](https://ideone.com/PNuVM5) – TartanLlama

+0

這是超級的,但我忘了說我不需要真正的隨機,而且我需要知道生成對象之前的一些信息。 例如,孩子clasess包含一些整數的字段。我需要從包含這個整數的隨機子類中生成對象,它大於30. 因此,具有<30的一些整數的類不會參與生成。 –

+0

這將允許@AntonIvanov只創建一個隨機對象4次,或不是? – NathanielSantley

0
#define MAX_CHILD_COUNT 3 
    A* A::GetRandomObject() 
    { 
     int _rand_index = rand()%MAX_CHILD_COUNT; // srand() before you call rand; 
     switch(_rand_index) 
     { 
      case 0: 
       return (new B1()); 
      case 1: 
       return (new B2()); 
      default: 
       return (new B3()); 
     } 
    } 

,因爲這?