0

假设我有一个名为 ItemOne、ItemTwo、ItemThree 和 ItemFour 的类的列表,它们都是 ItemBase 的子类。

我想在另一个名为 ItemGenerator 的类中有一个构造函数,它接受任何这些类的名称。我该怎么做?

ItemGenerator *someItem = new ItemGenerator(ItemThree);

另一种选择是在其中一个类上传递一个静态函数,但同样,我不知道该怎么做。

ItemGenerator *someItem = new ItemGenerator(ItemOne::start());

谢谢。

4

7 回答 7

1

您可以使用模板:

struct ItemBase {virtual ~ItemBase();};
struct ItemOne : ItemBase {};
struct ItemTwo : ItemBase {};
struct ItemThree : ItemBase {};
struct ItemFour : ItemBase {};

struct ItemGeneratorBase {
    virtual unique_ptr<ItemBase> generate() {}
    virtual ~ItemGeneratorBase() {}
};
template<typename Item>
struct ItemGenerator : ItemGeneratorBase {
    virtual unique_ptr<ItemBase> generate() {
        return unique_ptr<ItemBase>(new Item());
    }
};

std::unique_ptr<ItemGeneratorBase> someItem(new ItemGenerator<ItemThree>());
于 2013-03-01T16:38:27.590 回答
1

您真的要传递名称,即字符串吗?然后您必须为 Item*-classes 提供相应的功能,例如

class ItemOne {
  static std::string name();
};

ItemGenerator *someItem = new ItemGenerator(ItemThree::name());

或者您正在寻找模板?你有不同的可能性:制作一个类模板,可能从 ItemGenerator 基类派生:

class AbstractItemGenerator { /* ... */ };

template <class Item>
class ItemGenerator {
  ItemGenerator();
};

ItemGeneratorBase *someItem = new ItemGenerator<ItemTwo>();

或仅将构造函数模板化 - 您不能显式指定参数,因此使用参数推导:

//take 1: use pointers
class ItemGenerator {
  template <class Item>
  ItemGenerator(Item* dummy);
};

ItemGenerator *someItem = new ItemGenerator((ItemFour*)NULL);

//take 2: use a tag struct
template <class I>
struct ItemTag{};

class ItemGenerator {
  template <class Item>
  ItemGenerator(ItemTag<Item> tag);
};

ItemGenerator *someItem = new ItemGenerator(ItemTag<ItemOne>());

我不确定其中之一是否适合您的需求。也许详细说明你想用它做什么。

于 2013-03-01T16:45:12.427 回答
0

As the other answers indicate, you can achieve using templates.

Just to offer another idea, you can pass a function pointer that creates an instance of whatever you want (or whatever it is you want to do with that class)

ItemGenerator(ItemClassPtr itemClassFn)
{
    void * myObject = itemClassFn();
}
于 2013-03-01T16:42:59.137 回答
0

函数不能接受类名作为参数,因为类不是 C++ 中的对象。但是模板函数可以通过类名参数化。

像这样的东西:

template<class T> 
ItemGenerator* ItemGeneratorFactory() { T::start(); ...}

ItemGenerator *someItem = ItemGeneratorFactory<ItemThree>();
于 2013-03-01T16:35:57.910 回答
0

在不知道ItemGenerator.

正如 Mankarse 所说,一种解决方案是使用模板将您的类传递给生成器。

然而,如果ItemGenerator不能被模板化或者你不想在这里使用模板,你仍然可以按照你的建议通过使用 std::function 或 boost::function 来传递一个函数。

还有一些库可以帮助您向 c++ 添加反射。我记得CAMP,但我不知道它是否仍然有效。您可能会在那里找到解决问题的方法。

于 2013-03-01T18:53:53.557 回答
0

我有点生疏,但我很确定你可以只放入ItemBase构造函数,它会接受所有子类。

ItemGenerator::ItemGenerator(ItemBase base){\\do something with base
}

或者,如果使用模板不起作用,您可以创建多个构造函数:

ItemGenerator::ItemGenerator(ItemOne one){}
ItemGenerator::ItemGenerator(ItemTwo two){}
...
于 2013-03-01T16:44:33.683 回答
0

这正是工厂设计模式所做的。基本上在 ItemGenerator 类中有一个静态方法可以返回指向 ItemBase 对象的指针,但可以根据静态方法的参数返回指向 Item1、Item2 等的指针。

例如,在 ItemGenerator 类中,

static ItemBase *Generate( <any parameter> )
{
    switch (parameter)
    {
        case Value1: return new Item1();
        ...
        ...
     }
 }
于 2013-03-01T16:45:20.303 回答