【问题标题】:How to create object from random child class?如何从随机子类创建对象?
【发布时间】:2015-05-29 08:58:57
【问题描述】:

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

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

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

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

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

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

例如,子类包含带有一些整数的静态字段。我需要从包含这个整数的随机子类生成对象,它> 30(或其他类型的字段)。 因此,一些整数

【问题讨论】:

  • 没关系。我只是想解决问题。我需要从子类中获取随机对象。如何做到这一点并不重要。
  • 你有子类的集合吗?也许是指向基类的指针向量?然后只需随机选择其中一个元素。但是,如果您没有自己的对象集合,则不可能找到所有已分配和实例化的对象。
  • 你到底在坚持什么?如何生成随机数?如何创建新对象?
  • 子类的集合是什么?我不知道如何存储子类以便在他们之后调用。
  • @nwp,我知道如何生成随机数。我不知道如何从随机类创建对象。如果我可以将类存储在数组中...

标签: c++ oop


【解决方案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...
}

更新:
如果您的方法可能不知道所有可能的子类,则可以使用注册机制,在其中存储返回新实例(工厂)的 functionoid。

简要概述:

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

【讨论】:

  • 这个方法很好,但是子类会比较多,如果能动态添加新的子类,这个方法就更好了。
【解决方案2】:

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

【讨论】:

  • 这太棒了,但我忘了说我不需要真正的随机,我需要在生成对象之前知道一些信息。例如,子类包含带有一些整数的字段。我需要从包含这个整数的随机子类生成对象,它> 30。因此,一些整数
  • 这是否允许@AntonIvanov 只创建一个随机对象 4 次,还是不允许?
【解决方案3】:
    #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());
        }
    }

这样吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-10
    • 2017-05-28
    • 1970-01-01
    相关资源
    最近更新 更多