简体   繁体   中英

C++ - Use Class Name As Function Parameter

Say I have list of of classes called ItemOne, ItemTwo, ItemThree and ItemFour, which are all subclasses of ItemBase.

I would like to have a constructor in another class called ItemGenerator that accepts the name of any of these classes. How would I do this?

ItemGenerator *someItem = new ItemGenerator(ItemThree);

Another option would be to pass a static function on one of these classes, but again, I have no idea how to do that.

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

Thanks.

You could use a template:

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

Function cannot accept name of a class as a parameter, as class is not an object in C++. But template-function can be parametrized by a class name.

Something like this:

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

ItemGenerator *someItem = ItemGeneratorFactory<ItemThree>();

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();
}

I'm a little rusty, but I'm pretty sure you could just put ItemBase in the constructor and it would accept all subclasses.

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

or, if that and using a template don't work, you could create multiple constructors:

ItemGenerator::ItemGenerator(ItemOne one){}
ItemGenerator::ItemGenerator(ItemTwo two){}
...

Do you really want to pass the name , ie a string? Then you'd have to provide the Item*-classes with a corresponding function, eg

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

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

Or are you looking for templates? You have different possibilities there: make a class template, maybe derived from an ItemGenerator base class:

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

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

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

Or make only the construtor templated - you cannot explicitly specify the parameter, so use argumet deduction:

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

I am not sure if one of these suits your needs. Maybe elaborate what you want to use this for.

This is exactly what the Factory design pattern does. Basically there is a static method in the ItemGenerator class that can return pointers to ItemBase objects, but can return pointers to Item1, Item2 etc depending on the parameters to the static method.

For instance, in the ItemGenerator class,

static ItemBase *Generate( <any parameter> )
{
    switch (parameter)
    {
        case Value1: return new Item1();
        ...
        ...
     }
 }

It is difficult to find a solution to your problem without knowing the purpose of ItemGenerator .

As Mankarse says, one solution would be to use a template to pass your class to the generator.

Nevertheless, if ItemGenerator cannot be templated or if you do not want to use the templates here, you can still pass a function as you suggest by using either std::function or boost::function.

There are also some libraries that can help you to add reflexion to c++. I remember of CAMP but I do not know if it is still active. You may find a solution for your problem there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM