如何从随机子类创建对象

How to create object from random child class?

本文关键字:子类 创建对象 随机      更新时间:2023-10-16

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

我想写一些类似的东西(或者用另一种方式来做这件事,这无关紧要(:

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

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

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

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

例如,子类包含带有一些整数的静态字段。我需要从包含这个整数的随机子类中生成对象,并且它>30(或者使用其他类型的字段(。因此,具有一些整数<30岁的人不会参与这一代。

我假设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);

这假设您事先知道所有子类。如果没有,您可以创建一个带有一些虚拟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;
}
    #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());
        }
    }

像这样?