问题
In C++ is there a way to pass a type (e.g. a class) as parameter to a function?
Explanation why I need this: There is a abstract data
class and a manager
class. The manager
class contains a list (or in this case a map) of objects of derived classes of data
. I use unique_ptr
for this as mentioned in the answer of this question.
class Data{}; // abstract
class Manager
{
map<string, unique_ptr<Data>> List;
};
Now imagine I want to add a new data
storage to the manager.
class Position : public Data
{
int X;
int Y;
}
How could I tell the manager to create a object of that type and refer an unique_ptr
to it?
Manager manager;
manager.Add("position data", Position);
In this case I would need to pass the class Position
to the add
function of the manager class since I don't want to have to first create an instance and then send it to the manager.
And then, how could I add the object of that class to the List
?
I am not sure if there is a way of doing that in C++. If that can't be done easily I would really like to see a workaround. Thanks a lot!
回答1:
You can use templates. In each type deriving from Data
you will have to define a 'creator' function, which have the following prototype: Derived* create()
. It will be called internally (you can also return a unique_ptr
, but that would requires more memory).
Ex:
struct Position: public Data
{
// ...
static Position* create()
{
return new Position();
}
};
The Add
method will be:
template<typename D>
void Add(String str)
{
List.insert(std::make_pair(str, std::unique_ptr<Data>(D::create())));
}
Then you use it like this:
Manager manager;
manager.Add<Position>("position data");
EDIT
You can also get rid of the create
functions, by using this Add
method:
template<typename D>
void Add(String str)
{
List.insert(std::make_pair(str, std::unique_ptr<Data>(new D())));
}
Advantage: less code in data structure code.
Inconvenient: data structures have less control on how they're built.
回答2:
What about something like this:
class Manager
{
public:
template <typename T>
void addData(const std::string& title)
{
List.insert(std::make_pair(title, std::unique_ptr<Data>(new T));
}
private:
map<string, unique_ptr<Data>> List;
};
then
Manager manager;
manager.addData<Position>("position data");
回答3:
Using unique_ptr
means committing to working with dynamically allocated objects. (Not quite true: you could supply a custom deleter that doesn't call delete
, but that becomes part of the type; this means you would be committing to working with non-dynamically allocated objects.)
void Manager::Add(String title, unique_ptr<Data> d) {
List[title] = d;
}
Call it as:
Manager manager;
unique_ptr<Data> pos(new Position);
// Set it up
manager.Add("position data", pos);
Note: If you want to be able to do anything with your data objects, you probably want to declare at least one virtual function inside class Data
.
回答4:
Define the function as following:
void Manager::Add(String title,Position pos){ /*snip*/ }
Then you can use the function as following:
Manager manager;
Position posData;
//setup the posData
manager.Add("position data",posData);
来源:https://stackoverflow.com/questions/13109356/how-to-pass-a-class-as-parameter