This is easier to explain with some code so I’ll give an example first:
#include <iostream>
#include <vector>
class Base {
public:
int integer;
Base() : integer(0) {}
Base(int i) : integer(i) {}
};
class Double: public Base {
public:
Double(int i) { integer = i * 2; }
};
class Triple: public Base {
public:
Triple(int i) { integer = i * 3; }
};
template<typename T>
Base* createBaseObject(int i) {
return new T(i);
};
int main() {
std::vector<Base*> objects;
objects.push_back(createBaseObject<Double>(2));
objects.push_back(createBaseObject<Triple>(2));
for(int i = 0; i < objects.size(); ++i) {
std::cout << objects[i]->integer << std::endl;
}
std::cin.get();
return 0;
}
I am trying to make a function that will return a Base pointer to an object that is derived from Base. In the above code the function createBaseObject allows me to do that but it restricts me in that it can only create dervied classes that take a single argument into their constructor.
For example if I wanted to make a derived class Multiply:
class Multiply: public Base {
public:
Multiply(int i, int amount) { integer = i * amount; }
};
createBaseObject wouldn’t be able to create a Multiply object as it’s constructor takes two arguments.
I want to ultimately do something like this:
struct BaseCreator {
typedef Base* (*funcPtr)(int);
BaseCreator(std::string name, funcPtr f) : identifier(name), func(f) {}
std::string identifier;
funcPtr func;
};
then, for example, when I get input matching identifier I can create a new object of whatever derived class associates with that identifier with whatever arguments were input too and push it to the container.
After reading some of the replies I think something like this would suit my needs to be able to procedurally create an instance of an object? I’m not too wise with templates though so I do not know whether this is legal.
struct CreatorBase {
std::string identifier;
CreatorBase(std::string name) : identifier(name) {}
template<typename... Args>
virtual Base* createObject(Args... as) = 0;
};
template<typename T>
struct Creator: public CreatorBase {
typedef T type;
template<typename... Args>
Base* createObject(Args... as) {
return new type(as...);
}
};
Okay here’s another semi-solution I’ve managed to come up with so far:
#include <boost\lambda\bind.hpp>
#include <boost\lambda\construct.hpp>
#include <boost\function.hpp>
using namespace boost::lambda;
boost::function<Base(int)> dbl = bind(constructor<Double>(), _1);
boost::function<Base(int, int)> mult = bind(constructor<Multiply>(), _1, _2);
Just this has the same limits as the original in that I can’t have a single pointer that will point to both dbl and mult.
C++11 variadic templates can do this for you.
You already have your new derived class:
Then change your factory:
And, finally, allow the arguments to be deduced:
Live demo.
As others have said, though, it does all seem a little pointless. Presumably your true use case is less contrived.