The main trick that you seem to want is the virtual constructor idiom. Here is a simple example
Code:
#include <boost/shared_ptr.hpp>
class cloneable {
public:
cloneable() {std::cout << "ctor(default)" << std::endl;}
cloneable(const cloneable &o) {std::cout << "ctor(copy)" << std::endl;}
typedef boost::shared_ptr<cloneable> handle;
virtual handle clone() const = 0;
virtual std::istream & parse(std::istream &is) = 0;
virtual ~cloneable() {}
};
// dynamic dispatch, one operator for all
std::istream & operator >> (std::istream &is, cloneable &clone) {
return clone.parse(is);
}
class bigWidget : public cloneable {
int x,y;
public:
bigWidget() : x(0), y(0) {}
virtual handle clone() const {return handle(new bigWidget(*this));}
virtual std::istream & parse(std::istream &is) {
char ch;
if(is >> ch && ch != '(') is.setstate(std::ios_base::failbit);
int tx;
if(is >> tx >> ch && ch != ',') is.setstate(std::ios_base::failbit);
int ty;
if(is >> ty >> ch && ch == ')') {
x = tx; y = ty; // no syntax errors
} else is.setstate(std::ios_base::failbit);
return is;
}
virtual
~bigWidget() {std::cout << "Dead Big Widget ("<<x << ", " << y << ')' << std::endl;}
};
class smallWidget : public cloneable {
int x,y;
public:
smallWidget(int xx, int yy) : x(xx), y(yy) {}
virtual handle clone() const {return handle(new smallWidget(*this));}
virtual std::istream & parse(std::istream &is) {
char ch;
if(is >> x >> ch >> y && ch != ',') is.setstate(std::ios_base::failbit);
return is;
}
virtual
~smallWidget() {std::cout << "Dead smallWidget " << x << ", " << y << std::endl;}
};
class factory {
typedef cloneable::handle handle;
typedef std::map<std::string, handle> map_t;
map_t map;
public:
factory() {
handle h(new bigWidget);
map["bigWidget"] = h; // only one bigWidget
map["smallWidget"] = smallWidget(3,4).clone(); // temporary and heap
}
handle gen(const std::string & type) const {
map_t::const_iterator it = map.find(type);
return (it != map.end())?it->second->clone():handle();
}
handle parse(std::istream &is) const {
std::string type;
if(is >> type) {
handle clone = gen(type);
if(clone && is >> *clone) return clone;
}
return handle();
}
};
void test() {
factory f;
cloneable::handle h;
while((h = f.parse(std::cin)) && std::cin) std::cout << "OK!\n";
std::cout << "Out of loop" << std::endl;
}
Ok, perhaps not so simple, its kinda fun though.
This sets up a syntax for your configuration file where you prefix each type with the key for the map in the factory. each decenant of cloneable implements a virtual parse method, that ends up being a "virtual" operator >>. The factory parse method can then build decendants of cloneable without knowing anything about them. The boost::shared_ptr's solve a lot of hassles, but handles could be simple pointers, if you remmeber to call delete.