如何从随机子类创建对象?

时间:2015-05-29 08:58:58

标签: c++ oop

例如,我有基类A和子类B1,B2,B3等。

我想写一些类似的东西(或其他方式来做,这没关系):

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

randomobject1是指向随机子类的对象的指针。

我不知道怎么做!也许我需要存储对子方法的引用并在之后调用它,或者......我不明白。

我不需要真正的随机,我需要在生成对象之前知道一些信息。

例如,子类包含带有一些整数的静态字段。我需要从包含这个整数的随机子类生成对象,它是> 30(或与另一种类型的领域)。 所以,有一些整数的类< 30将不会参与世代。

3 个答案:

答案 0 :(得分: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...
}

<强>更新
如果您的方法可能不知道所有可能的子类,则可能存在注册机制,您可以存储返回新实例(工厂)的函数。

快速概述:

// 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;

这是一个创建结构并在全局范围内创建虚拟实例的makro。在其构造函数中,子类已注册。

您可以在子类CPP文件中使用它,例如:

REGISTER_A(B1);

答案 1 :(得分: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;
}

答案 2 :(得分: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());
        }
    }

这个?

相关问题